Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 1045:f535f6e5dbb0 alignment-simple
Merge in from SV 3.0-integration branches
author | Chris Cannam |
---|---|
date | Wed, 02 Mar 2016 17:25:27 +0000 |
parents | 4e5c1c326794 |
children | 5e5873c24142 |
comparison
equal
deleted
inserted
replaced
976:f2c63ec85901 | 1045:f535f6e5dbb0 |
---|---|
31 | 31 |
32 #include <QPainter> | 32 #include <QPainter> |
33 #include <QImage> | 33 #include <QImage> |
34 #include <QPixmap> | 34 #include <QPixmap> |
35 #include <QRect> | 35 #include <QRect> |
36 #include <QTimer> | |
37 #include <QApplication> | 36 #include <QApplication> |
38 #include <QMessageBox> | 37 #include <QMessageBox> |
39 #include <QMouseEvent> | 38 #include <QMouseEvent> |
40 #include <QTextStream> | 39 #include <QTextStream> |
40 #include <QSettings> | |
41 | 41 |
42 #include <iostream> | 42 #include <iostream> |
43 | 43 |
44 #include <cassert> | 44 #include <cassert> |
45 #include <cmath> | 45 #include <cmath> |
46 | 46 |
47 #ifndef __GNUC__ | 47 #ifndef __GNUC__ |
48 #include <alloca.h> | 48 #include <alloca.h> |
49 #endif | 49 #endif |
50 | 50 |
51 //#define DEBUG_SPECTROGRAM_REPAINT 1 | 51 #define DEBUG_SPECTROGRAM_REPAINT 1 |
52 | 52 |
53 using std::vector; | 53 using namespace std; |
54 | 54 |
55 SpectrogramLayer::SpectrogramLayer(Configuration config) : | 55 SpectrogramLayer::SpectrogramLayer(Configuration config) : |
56 m_model(0), | 56 m_model(0), |
57 m_channel(0), | 57 m_channel(0), |
58 m_windowSize(1024), | 58 m_windowSize(1024), |
71 m_initialMaxFrequency(8000), | 71 m_initialMaxFrequency(8000), |
72 m_colourScale(dBColourScale), | 72 m_colourScale(dBColourScale), |
73 m_colourMap(0), | 73 m_colourMap(0), |
74 m_frequencyScale(LinearFrequencyScale), | 74 m_frequencyScale(LinearFrequencyScale), |
75 m_binDisplay(AllBins), | 75 m_binDisplay(AllBins), |
76 m_normalizeColumns(false), | 76 m_normalization(NoNormalization), |
77 m_normalizeVisibleArea(false), | |
78 m_normalizeHybrid(false), | |
79 m_lastEmittedZoomStep(-1), | 77 m_lastEmittedZoomStep(-1), |
80 m_synchronous(false), | 78 m_synchronous(false), |
81 m_haveDetailedScale(false), | 79 m_haveDetailedScale(false), |
82 m_lastPaintBlockWidth(0), | |
83 m_updateTimer(0), | |
84 m_candidateFillStartFrame(0), | |
85 m_exiting(false), | 80 m_exiting(false), |
86 m_sliceableModel(0) | 81 m_sliceableModel(0) |
87 { | 82 { |
83 QString colourConfigName = "spectrogram-colour"; | |
84 int colourConfigDefault = int(ColourMapper::Green); | |
85 | |
88 if (config == FullRangeDb) { | 86 if (config == FullRangeDb) { |
89 m_initialMaxFrequency = 0; | 87 m_initialMaxFrequency = 0; |
90 setMaxFrequency(0); | 88 setMaxFrequency(0); |
91 } else if (config == MelodicRange) { | 89 } else if (config == MelodicRange) { |
92 setWindowSize(8192); | 90 setWindowSize(8192); |
95 setMaxFrequency(1500); | 93 setMaxFrequency(1500); |
96 setMinFrequency(40); | 94 setMinFrequency(40); |
97 setColourScale(LinearColourScale); | 95 setColourScale(LinearColourScale); |
98 setColourMap(ColourMapper::Sunset); | 96 setColourMap(ColourMapper::Sunset); |
99 setFrequencyScale(LogFrequencyScale); | 97 setFrequencyScale(LogFrequencyScale); |
98 colourConfigName = "spectrogram-melodic-colour"; | |
99 colourConfigDefault = int(ColourMapper::Sunset); | |
100 // setGain(20); | 100 // setGain(20); |
101 } else if (config == MelodicPeaks) { | 101 } else if (config == MelodicPeaks) { |
102 setWindowSize(4096); | 102 setWindowSize(4096); |
103 setWindowHopLevel(5); | 103 setWindowHopLevel(5); |
104 m_initialMaxFrequency = 2000; | 104 m_initialMaxFrequency = 2000; |
105 setMaxFrequency(2000); | 105 setMaxFrequency(2000); |
106 setMinFrequency(40); | 106 setMinFrequency(40); |
107 setFrequencyScale(LogFrequencyScale); | 107 setFrequencyScale(LogFrequencyScale); |
108 setColourScale(LinearColourScale); | 108 setColourScale(LinearColourScale); |
109 setBinDisplay(PeakFrequencies); | 109 setBinDisplay(PeakFrequencies); |
110 setNormalizeColumns(true); | 110 setNormalization(NormalizeColumns); |
111 } | 111 colourConfigName = "spectrogram-melodic-colour"; |
112 | 112 colourConfigDefault = int(ColourMapper::Sunset); |
113 } | |
114 | |
115 QSettings settings; | |
116 settings.beginGroup("Preferences"); | |
117 setColourMap(settings.value(colourConfigName, colourConfigDefault).toInt()); | |
118 settings.endGroup(); | |
119 | |
113 Preferences *prefs = Preferences::getInstance(); | 120 Preferences *prefs = Preferences::getInstance(); |
114 connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)), | 121 connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)), |
115 this, SLOT(preferenceChanged(PropertyContainer::PropertyName))); | 122 this, SLOT(preferenceChanged(PropertyContainer::PropertyName))); |
116 setWindowType(prefs->getWindowType()); | 123 setWindowType(prefs->getWindowType()); |
117 | 124 |
118 initialisePalette(); | 125 initialisePalette(); |
119 } | 126 } |
120 | 127 |
121 SpectrogramLayer::~SpectrogramLayer() | 128 SpectrogramLayer::~SpectrogramLayer() |
122 { | 129 { |
123 delete m_updateTimer; | |
124 m_updateTimer = 0; | |
125 | |
126 invalidateFFTModels(); | 130 invalidateFFTModels(); |
127 } | 131 } |
128 | 132 |
129 void | 133 void |
130 SpectrogramLayer::setModel(const DenseTimeValueModel *model) | 134 SpectrogramLayer::setModel(const DenseTimeValueModel *model) |
153 PropertyList list; | 157 PropertyList list; |
154 list.push_back("Colour"); | 158 list.push_back("Colour"); |
155 list.push_back("Colour Scale"); | 159 list.push_back("Colour Scale"); |
156 list.push_back("Window Size"); | 160 list.push_back("Window Size"); |
157 list.push_back("Window Increment"); | 161 list.push_back("Window Increment"); |
158 list.push_back("Normalize Columns"); | 162 list.push_back("Normalization"); |
159 list.push_back("Normalize Visible Area"); | |
160 list.push_back("Bin Display"); | 163 list.push_back("Bin Display"); |
161 list.push_back("Threshold"); | 164 list.push_back("Threshold"); |
162 list.push_back("Gain"); | 165 list.push_back("Gain"); |
163 list.push_back("Colour Rotation"); | 166 list.push_back("Colour Rotation"); |
164 // list.push_back("Min Frequency"); | 167 // list.push_back("Min Frequency"); |
173 { | 176 { |
174 if (name == "Colour") return tr("Colour"); | 177 if (name == "Colour") return tr("Colour"); |
175 if (name == "Colour Scale") return tr("Colour Scale"); | 178 if (name == "Colour Scale") return tr("Colour Scale"); |
176 if (name == "Window Size") return tr("Window Size"); | 179 if (name == "Window Size") return tr("Window Size"); |
177 if (name == "Window Increment") return tr("Window Overlap"); | 180 if (name == "Window Increment") return tr("Window Overlap"); |
178 if (name == "Normalize Columns") return tr("Normalize Columns"); | 181 if (name == "Normalization") return tr("Normalization"); |
179 if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); | |
180 if (name == "Bin Display") return tr("Bin Display"); | 182 if (name == "Bin Display") return tr("Bin Display"); |
181 if (name == "Threshold") return tr("Threshold"); | 183 if (name == "Threshold") return tr("Threshold"); |
182 if (name == "Gain") return tr("Gain"); | 184 if (name == "Gain") return tr("Gain"); |
183 if (name == "Colour Rotation") return tr("Colour Rotation"); | 185 if (name == "Colour Rotation") return tr("Colour Rotation"); |
184 if (name == "Min Frequency") return tr("Min Frequency"); | 186 if (name == "Min Frequency") return tr("Min Frequency"); |
187 if (name == "Zero Padding") return tr("Smoothing"); | 189 if (name == "Zero Padding") return tr("Smoothing"); |
188 return ""; | 190 return ""; |
189 } | 191 } |
190 | 192 |
191 QString | 193 QString |
192 SpectrogramLayer::getPropertyIconName(const PropertyName &name) const | 194 SpectrogramLayer::getPropertyIconName(const PropertyName &) const |
193 { | 195 { |
194 if (name == "Normalize Columns") return "normalise-columns"; | |
195 if (name == "Normalize Visible Area") return "normalise"; | |
196 return ""; | 196 return ""; |
197 } | 197 } |
198 | 198 |
199 Layer::PropertyType | 199 Layer::PropertyType |
200 SpectrogramLayer::getPropertyType(const PropertyName &name) const | 200 SpectrogramLayer::getPropertyType(const PropertyName &name) const |
201 { | 201 { |
202 if (name == "Gain") return RangeProperty; | 202 if (name == "Gain") return RangeProperty; |
203 if (name == "Colour Rotation") return RangeProperty; | 203 if (name == "Colour Rotation") return RangeProperty; |
204 if (name == "Normalize Columns") return ToggleProperty; | |
205 if (name == "Normalize Visible Area") return ToggleProperty; | |
206 if (name == "Threshold") return RangeProperty; | 204 if (name == "Threshold") return RangeProperty; |
207 if (name == "Zero Padding") return ToggleProperty; | 205 if (name == "Zero Padding") return ToggleProperty; |
208 return ValueProperty; | 206 return ValueProperty; |
209 } | 207 } |
210 | 208 |
217 name == "Window Increment" || | 215 name == "Window Increment" || |
218 name == "Zero Padding") return tr("Window"); | 216 name == "Zero Padding") return tr("Window"); |
219 if (name == "Colour" || | 217 if (name == "Colour" || |
220 name == "Threshold" || | 218 name == "Threshold" || |
221 name == "Colour Rotation") return tr("Colour"); | 219 name == "Colour Rotation") return tr("Colour"); |
222 if (name == "Normalize Columns" || | 220 if (name == "Normalization" || |
223 name == "Normalize Visible Area" || | |
224 name == "Gain" || | 221 name == "Gain" || |
225 name == "Colour Scale") return tr("Scale"); | 222 name == "Colour Scale") return tr("Scale"); |
226 return QString(); | 223 return QString(); |
227 } | 224 } |
228 | 225 |
363 *min = 0; | 360 *min = 0; |
364 *max = 2; | 361 *max = 2; |
365 *deflt = int(AllBins); | 362 *deflt = int(AllBins); |
366 val = (int)m_binDisplay; | 363 val = (int)m_binDisplay; |
367 | 364 |
368 } else if (name == "Normalize Columns") { | 365 } else if (name == "Normalization") { |
369 | 366 |
370 *deflt = 0; | 367 *min = 0; |
371 val = (m_normalizeColumns ? 1 : 0); | 368 *max = 3; |
372 | 369 *deflt = int(NoNormalization); |
373 } else if (name == "Normalize Visible Area") { | 370 val = (int)m_normalization; |
374 | |
375 *deflt = 0; | |
376 val = (m_normalizeVisibleArea ? 1 : 0); | |
377 | 371 |
378 } else { | 372 } else { |
379 val = Layer::getPropertyRangeAndValue(name, min, max, deflt); | 373 val = Layer::getPropertyRangeAndValue(name, min, max, deflt); |
380 } | 374 } |
381 | 375 |
396 case 1: return tr("Meter"); | 390 case 1: return tr("Meter"); |
397 case 2: return tr("dBV^2"); | 391 case 2: return tr("dBV^2"); |
398 case 3: return tr("dBV"); | 392 case 3: return tr("dBV"); |
399 case 4: return tr("Phase"); | 393 case 4: return tr("Phase"); |
400 } | 394 } |
395 } | |
396 if (name == "Normalization") { | |
397 return ""; // icon only | |
401 } | 398 } |
402 if (name == "Window Size") { | 399 if (name == "Window Size") { |
403 return QString("%1").arg(32 << value); | 400 return QString("%1").arg(32 << value); |
404 } | 401 } |
405 if (name == "Window Increment") { | 402 if (name == "Window Increment") { |
461 case 1: return tr("Peak Bins"); | 458 case 1: return tr("Peak Bins"); |
462 case 2: return tr("Frequencies"); | 459 case 2: return tr("Frequencies"); |
463 } | 460 } |
464 } | 461 } |
465 return tr("<unknown>"); | 462 return tr("<unknown>"); |
463 } | |
464 | |
465 QString | |
466 SpectrogramLayer::getPropertyValueIconName(const PropertyName &name, | |
467 int value) const | |
468 { | |
469 if (name == "Normalization") { | |
470 switch(value) { | |
471 default: | |
472 case 0: return "normalise-none"; | |
473 case 1: return "normalise-columns"; | |
474 case 2: return "normalise"; | |
475 case 3: return "normalise-hybrid"; | |
476 } | |
477 } | |
478 return ""; | |
466 } | 479 } |
467 | 480 |
468 RangeMapper * | 481 RangeMapper * |
469 SpectrogramLayer::getNewPropertyRangeMapper(const PropertyName &name) const | 482 SpectrogramLayer::getNewPropertyRangeMapper(const PropertyName &name) const |
470 { | 483 { |
553 default: | 566 default: |
554 case 0: setBinDisplay(AllBins); break; | 567 case 0: setBinDisplay(AllBins); break; |
555 case 1: setBinDisplay(PeakBins); break; | 568 case 1: setBinDisplay(PeakBins); break; |
556 case 2: setBinDisplay(PeakFrequencies); break; | 569 case 2: setBinDisplay(PeakFrequencies); break; |
557 } | 570 } |
558 } else if (name == "Normalize Columns") { | 571 } else if (name == "Normalization") { |
559 setNormalizeColumns(value ? true : false); | 572 switch (value) { |
560 } else if (name == "Normalize Visible Area") { | 573 default: |
561 setNormalizeVisibleArea(value ? true : false); | 574 case 0: setNormalization(NoNormalization); break; |
575 case 1: setNormalization(NormalizeColumns); break; | |
576 case 2: setNormalization(NormalizeVisibleArea); break; | |
577 case 3: setNormalization(NormalizeHybrid); break; | |
578 } | |
562 } | 579 } |
563 } | 580 } |
564 | 581 |
565 void | 582 void |
566 SpectrogramLayer::invalidateImageCaches() | 583 SpectrogramLayer::invalidateImageCaches() |
567 { | 584 { |
585 #ifdef DEBUG_SPECTROGRAM | |
586 cerr << "SpectrogramLayer::invalidateImageCaches called" << endl; | |
587 #endif | |
568 for (ViewImageCache::iterator i = m_imageCaches.begin(); | 588 for (ViewImageCache::iterator i = m_imageCaches.begin(); |
569 i != m_imageCaches.end(); ++i) { | 589 i != m_imageCaches.end(); ++i) { |
570 i->second.validArea = QRect(); | 590 i->second.invalidate(); |
571 } | |
572 } | |
573 | |
574 void | |
575 SpectrogramLayer::invalidateImageCaches(sv_frame_t startFrame, sv_frame_t endFrame) | |
576 { | |
577 for (ViewImageCache::iterator i = m_imageCaches.begin(); | |
578 i != m_imageCaches.end(); ++i) { | |
579 | |
580 //!!! when are views removed from the map? on setLayerDormant? | |
581 const View *v = i->first; | |
582 | |
583 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
584 SVDEBUG << "SpectrogramLayer::invalidateImageCaches(" | |
585 << startFrame << ", " << endFrame << "): view range is " | |
586 << v->getStartFrame() << ", " << v->getEndFrame() | |
587 << endl; | |
588 | |
589 cerr << "Valid area was: " << i->second.validArea.x() << ", " | |
590 << i->second.validArea.y() << " " | |
591 << i->second.validArea.width() << "x" | |
592 << i->second.validArea.height() << endl; | |
593 #endif | |
594 | |
595 if (int(startFrame) > v->getStartFrame()) { | |
596 if (startFrame >= v->getEndFrame()) { | |
597 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
598 cerr << "Modified start frame is off right of view" << endl; | |
599 #endif | |
600 return; | |
601 } | |
602 int x = v->getXForFrame(startFrame); | |
603 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
604 SVDEBUG << "clipping from 0 to " << x-1 << endl; | |
605 #endif | |
606 if (x > 1) { | |
607 i->second.validArea &= | |
608 QRect(0, 0, x-1, v->height()); | |
609 } else { | |
610 i->second.validArea = QRect(); | |
611 } | |
612 } else { | |
613 if (int(endFrame) < v->getStartFrame()) { | |
614 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
615 cerr << "Modified end frame is off left of view" << endl; | |
616 #endif | |
617 return; | |
618 } | |
619 int x = v->getXForFrame(endFrame); | |
620 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
621 SVDEBUG << "clipping from " << x+1 << " to " << v->width() | |
622 << endl; | |
623 #endif | |
624 if (x < v->width()) { | |
625 i->second.validArea &= | |
626 QRect(x+1, 0, v->width()-(x+1), v->height()); | |
627 } else { | |
628 i->second.validArea = QRect(); | |
629 } | |
630 } | |
631 | |
632 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
633 cerr << "Valid area is now: " << i->second.validArea.x() << ", " | |
634 << i->second.validArea.y() << " " | |
635 << i->second.validArea.width() << "x" | |
636 << i->second.validArea.height() << endl; | |
637 #endif | |
638 } | 591 } |
639 } | 592 } |
640 | 593 |
641 void | 594 void |
642 SpectrogramLayer::preferenceChanged(PropertyContainer::PropertyName name) | 595 SpectrogramLayer::preferenceChanged(PropertyContainer::PropertyName name) |
932 { | 885 { |
933 return m_binDisplay; | 886 return m_binDisplay; |
934 } | 887 } |
935 | 888 |
936 void | 889 void |
937 SpectrogramLayer::setNormalizeColumns(bool n) | 890 SpectrogramLayer::setNormalization(Normalization n) |
938 { | 891 { |
939 if (m_normalizeColumns == n) return; | 892 if (m_normalization == n) return; |
940 | 893 |
941 invalidateImageCaches(); | 894 invalidateImageCaches(); |
942 invalidateMagnitudes(); | 895 invalidateMagnitudes(); |
943 m_normalizeColumns = n; | 896 m_normalization = n; |
944 | 897 |
945 emit layerParametersChanged(); | 898 emit layerParametersChanged(); |
946 } | 899 } |
947 | 900 |
948 bool | 901 SpectrogramLayer::Normalization |
949 SpectrogramLayer::getNormalizeColumns() const | 902 SpectrogramLayer::getNormalization() const |
950 { | 903 { |
951 return m_normalizeColumns; | 904 return m_normalization; |
952 } | 905 } |
953 | 906 |
954 void | 907 void |
955 SpectrogramLayer::setNormalizeHybrid(bool n) | 908 SpectrogramLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant) |
956 { | |
957 if (m_normalizeHybrid == n) return; | |
958 | |
959 invalidateImageCaches(); | |
960 invalidateMagnitudes(); | |
961 m_normalizeHybrid = n; | |
962 | |
963 emit layerParametersChanged(); | |
964 } | |
965 | |
966 bool | |
967 SpectrogramLayer::getNormalizeHybrid() const | |
968 { | |
969 return m_normalizeHybrid; | |
970 } | |
971 | |
972 void | |
973 SpectrogramLayer::setNormalizeVisibleArea(bool n) | |
974 { | |
975 SVDEBUG << "SpectrogramLayer::setNormalizeVisibleArea(" << n | |
976 << ") (from " << m_normalizeVisibleArea << ")" << endl; | |
977 | |
978 if (m_normalizeVisibleArea == n) return; | |
979 | |
980 invalidateImageCaches(); | |
981 invalidateMagnitudes(); | |
982 m_normalizeVisibleArea = n; | |
983 | |
984 emit layerParametersChanged(); | |
985 } | |
986 | |
987 bool | |
988 SpectrogramLayer::getNormalizeVisibleArea() const | |
989 { | |
990 return m_normalizeVisibleArea; | |
991 } | |
992 | |
993 void | |
994 SpectrogramLayer::setLayerDormant(const View *v, bool dormant) | |
995 { | 909 { |
996 if (dormant) { | 910 if (dormant) { |
997 | 911 |
998 #ifdef DEBUG_SPECTROGRAM_REPAINT | 912 #ifdef DEBUG_SPECTROGRAM_REPAINT |
999 SVDEBUG << "SpectrogramLayer::setLayerDormant(" << dormant << ")" | 913 cerr << "SpectrogramLayer::setLayerDormant(" << dormant << ")" |
1000 << endl; | 914 << endl; |
1001 #endif | 915 #endif |
1002 | 916 |
1003 if (isLayerDormant(v)) { | 917 if (isLayerDormant(v)) { |
1004 return; | 918 return; |
1005 } | 919 } |
1006 | 920 |
1007 Layer::setLayerDormant(v, true); | 921 Layer::setLayerDormant(v, true); |
1008 | 922 |
923 const View *view = v->getView(); | |
924 | |
1009 invalidateImageCaches(); | 925 invalidateImageCaches(); |
1010 m_imageCaches.erase(v); | 926 |
1011 | 927 m_imageCaches.erase(view->getId()); |
1012 if (m_fftModels.find(v) != m_fftModels.end()) { | 928 |
1013 | 929 if (m_fftModels.find(view->getId()) != m_fftModels.end()) { |
1014 if (m_sliceableModel == m_fftModels[v].first) { | 930 |
931 if (m_sliceableModel == m_fftModels[view->getId()]) { | |
1015 bool replaced = false; | 932 bool replaced = false; |
1016 for (ViewFFTMap::iterator i = m_fftModels.begin(); | 933 for (ViewFFTMap::iterator i = m_fftModels.begin(); |
1017 i != m_fftModels.end(); ++i) { | 934 i != m_fftModels.end(); ++i) { |
1018 if (i->second.first != m_sliceableModel) { | 935 if (i->second != m_sliceableModel) { |
1019 emit sliceableModelReplaced(m_sliceableModel, i->second.first); | 936 emit sliceableModelReplaced(m_sliceableModel, i->second); |
1020 replaced = true; | 937 replaced = true; |
1021 break; | 938 break; |
1022 } | 939 } |
1023 } | 940 } |
1024 if (!replaced) emit sliceableModelReplaced(m_sliceableModel, 0); | 941 if (!replaced) emit sliceableModelReplaced(m_sliceableModel, 0); |
1025 } | 942 } |
1026 | 943 |
1027 delete m_fftModels[v].first; | 944 delete m_fftModels[view->getId()]; |
1028 m_fftModels.erase(v); | 945 m_fftModels.erase(view->getId()); |
1029 | 946 |
1030 delete m_peakCaches[v]; | 947 delete m_peakCaches[view->getId()]; |
1031 m_peakCaches.erase(v); | 948 m_peakCaches.erase(view->getId()); |
1032 } | 949 } |
1033 | 950 |
1034 } else { | 951 } else { |
1035 | 952 |
1036 Layer::setLayerDormant(v, false); | 953 Layer::setLayerDormant(v, false); |
1039 | 956 |
1040 void | 957 void |
1041 SpectrogramLayer::cacheInvalid() | 958 SpectrogramLayer::cacheInvalid() |
1042 { | 959 { |
1043 #ifdef DEBUG_SPECTROGRAM_REPAINT | 960 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1044 SVDEBUG << "SpectrogramLayer::cacheInvalid()" << endl; | 961 cerr << "SpectrogramLayer::cacheInvalid()" << endl; |
1045 #endif | 962 #endif |
1046 | 963 |
1047 invalidateImageCaches(); | 964 invalidateImageCaches(); |
1048 invalidateMagnitudes(); | 965 invalidateMagnitudes(); |
1049 } | 966 } |
1050 | 967 |
1051 void | 968 void |
1052 SpectrogramLayer::cacheInvalid(sv_frame_t from, sv_frame_t to) | 969 SpectrogramLayer::cacheInvalid( |
1053 { | 970 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1054 #ifdef DEBUG_SPECTROGRAM_REPAINT | 971 sv_frame_t from, sv_frame_t to |
1055 SVDEBUG << "SpectrogramLayer::cacheInvalid(" << from << ", " << to << ")" << endl; | 972 #else |
1056 #endif | 973 sv_frame_t , sv_frame_t |
1057 | 974 #endif |
1058 invalidateImageCaches(from, to); | 975 ) |
976 { | |
977 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
978 cerr << "SpectrogramLayer::cacheInvalid(" << from << ", " << to << ")" << endl; | |
979 #endif | |
980 | |
981 // We used to call invalidateMagnitudes(from, to) to invalidate | |
982 // only those caches whose views contained some of the (from, to) | |
983 // range. That's the right thing to do; it has been lost in | |
984 // pulling out the image cache code, but it might not matter very | |
985 // much, since the underlying models for spectrogram layers don't | |
986 // change very often. Let's see. | |
987 invalidateImageCaches(); | |
1059 invalidateMagnitudes(); | 988 invalidateMagnitudes(); |
1060 } | |
1061 | |
1062 void | |
1063 SpectrogramLayer::fillTimerTimedOut() | |
1064 { | |
1065 if (!m_model) return; | |
1066 | |
1067 bool allDone = true; | |
1068 | |
1069 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1070 SVDEBUG << "SpectrogramLayer::fillTimerTimedOut: have " << m_fftModels.size() << " FFT models associated with views" << endl; | |
1071 #endif | |
1072 | |
1073 for (ViewFFTMap::iterator i = m_fftModels.begin(); | |
1074 i != m_fftModels.end(); ++i) { | |
1075 | |
1076 const FFTModel *model = i->second.first; | |
1077 sv_frame_t lastFill = i->second.second; | |
1078 | |
1079 if (model) { | |
1080 | |
1081 sv_frame_t fill = model->getFillExtent(); | |
1082 | |
1083 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1084 SVDEBUG << "SpectrogramLayer::fillTimerTimedOut: extent for " << model << ": " << fill << ", last " << lastFill << ", total " << m_model->getEndFrame() << endl; | |
1085 #endif | |
1086 | |
1087 if (fill >= lastFill) { | |
1088 if (fill >= m_model->getEndFrame() && lastFill > 0) { | |
1089 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1090 cerr << "complete!" << endl; | |
1091 #endif | |
1092 invalidateImageCaches(); | |
1093 i->second.second = -1; | |
1094 emit modelChanged(); | |
1095 | |
1096 } else if (fill > lastFill) { | |
1097 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1098 cerr << "SpectrogramLayer: emitting modelChanged(" | |
1099 << lastFill << "," << fill << ")" << endl; | |
1100 #endif | |
1101 invalidateImageCaches(lastFill, fill); | |
1102 i->second.second = fill; | |
1103 emit modelChangedWithin(lastFill, fill); | |
1104 } | |
1105 } else { | |
1106 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1107 cerr << "SpectrogramLayer: going backwards, emitting modelChanged(" | |
1108 << m_model->getStartFrame() << "," << m_model->getEndFrame() << ")" << endl; | |
1109 #endif | |
1110 invalidateImageCaches(); | |
1111 i->second.second = fill; | |
1112 emit modelChangedWithin(m_model->getStartFrame(), m_model->getEndFrame()); | |
1113 } | |
1114 | |
1115 if (i->second.second >= 0) { | |
1116 allDone = false; | |
1117 } | |
1118 } | |
1119 } | |
1120 | |
1121 if (allDone) { | |
1122 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1123 cerr << "SpectrogramLayer: all complete!" << endl; | |
1124 #endif | |
1125 delete m_updateTimer; | |
1126 m_updateTimer = 0; | |
1127 } | |
1128 } | 989 } |
1129 | 990 |
1130 bool | 991 bool |
1131 SpectrogramLayer::hasLightBackground() const | 992 SpectrogramLayer::hasLightBackground() const |
1132 { | 993 { |
1179 | 1040 |
1180 m_drawBuffer = QImage(); | 1041 m_drawBuffer = QImage(); |
1181 } | 1042 } |
1182 | 1043 |
1183 unsigned char | 1044 unsigned char |
1184 SpectrogramLayer::getDisplayValue(View *v, double input) const | 1045 SpectrogramLayer::getDisplayValue(LayerGeometryProvider *v, double input) const |
1185 { | 1046 { |
1186 int value; | 1047 int value; |
1187 | 1048 |
1188 double min = 0.0; | 1049 double min = 0.0; |
1189 double max = 1.0; | 1050 double max = 1.0; |
1190 | 1051 |
1191 if (m_normalizeVisibleArea) { | 1052 if (m_normalization == NormalizeVisibleArea) { |
1192 min = m_viewMags[v].getMin(); | 1053 min = m_viewMags[v->getId()].getMin(); |
1193 max = m_viewMags[v].getMax(); | 1054 max = m_viewMags[v->getId()].getMax(); |
1194 } else if (!m_normalizeColumns) { | 1055 } else if (m_normalization != NormalizeColumns) { |
1195 if (m_colourScale == LinearColourScale //|| | 1056 if (m_colourScale == LinearColourScale //|| |
1196 // m_colourScale == MeterColourScale) { | 1057 // m_colourScale == MeterColourScale) { |
1197 ) { | 1058 ) { |
1198 max = 0.1; | 1059 max = 0.1; |
1199 } | 1060 } |
1292 | 1153 |
1293 return maxf; | 1154 return maxf; |
1294 } | 1155 } |
1295 | 1156 |
1296 bool | 1157 bool |
1297 SpectrogramLayer::getYBinRange(View *v, int y, double &q0, double &q1) const | 1158 SpectrogramLayer::getYBinRange(LayerGeometryProvider *v, int y, double &q0, double &q1) const |
1298 { | 1159 { |
1299 Profiler profiler("SpectrogramLayer::getYBinRange"); | 1160 Profiler profiler("SpectrogramLayer::getYBinRange"); |
1300 | 1161 |
1301 int h = v->height(); | 1162 int h = v->getPaintHeight(); |
1302 if (y < 0 || y >= h) return false; | 1163 if (y < 0 || y >= h) return false; |
1303 | 1164 |
1304 sv_samplerate_t sr = m_model->getSampleRate(); | 1165 sv_samplerate_t sr = m_model->getSampleRate(); |
1305 double minf = getEffectiveMinFrequency(); | 1166 double minf = getEffectiveMinFrequency(); |
1306 double maxf = getEffectiveMaxFrequency(); | 1167 double maxf = getEffectiveMaxFrequency(); |
1318 | 1179 |
1319 return true; | 1180 return true; |
1320 } | 1181 } |
1321 | 1182 |
1322 bool | 1183 bool |
1323 SpectrogramLayer::getSmoothedYBinRange(View *v, int y, double &q0, double &q1) const | 1184 SpectrogramLayer::getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &q0, double &q1) const |
1324 { | 1185 { |
1325 Profiler profiler("SpectrogramLayer::getSmoothedYBinRange"); | 1186 Profiler profiler("SpectrogramLayer::getSmoothedYBinRange"); |
1326 | 1187 |
1327 int h = v->height(); | 1188 int h = v->getPaintHeight(); |
1328 if (y < 0 || y >= h) return false; | 1189 if (y < 0 || y >= h) return false; |
1329 | 1190 |
1330 sv_samplerate_t sr = m_model->getSampleRate(); | 1191 sv_samplerate_t sr = m_model->getSampleRate(); |
1331 double minf = getEffectiveMinFrequency(); | 1192 double minf = getEffectiveMinFrequency(); |
1332 double maxf = getEffectiveMaxFrequency(); | 1193 double maxf = getEffectiveMaxFrequency(); |
1344 | 1205 |
1345 return true; | 1206 return true; |
1346 } | 1207 } |
1347 | 1208 |
1348 bool | 1209 bool |
1349 SpectrogramLayer::getXBinRange(View *v, int x, double &s0, double &s1) const | 1210 SpectrogramLayer::getXBinRange(LayerGeometryProvider *v, int x, double &s0, double &s1) const |
1350 { | 1211 { |
1351 sv_frame_t modelStart = m_model->getStartFrame(); | 1212 sv_frame_t modelStart = m_model->getStartFrame(); |
1352 sv_frame_t modelEnd = m_model->getEndFrame(); | 1213 sv_frame_t modelEnd = m_model->getEndFrame(); |
1353 | 1214 |
1354 // Each pixel column covers an exact range of sample frames: | 1215 // Each pixel column covers an exact range of sample frames: |
1368 | 1229 |
1369 return true; | 1230 return true; |
1370 } | 1231 } |
1371 | 1232 |
1372 bool | 1233 bool |
1373 SpectrogramLayer::getXBinSourceRange(View *v, int x, RealTime &min, RealTime &max) const | 1234 SpectrogramLayer::getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &min, RealTime &max) const |
1374 { | 1235 { |
1375 double s0 = 0, s1 = 0; | 1236 double s0 = 0, s1 = 0; |
1376 if (!getXBinRange(v, x, s0, s1)) return false; | 1237 if (!getXBinRange(v, x, s0, s1)) return false; |
1377 | 1238 |
1378 int s0i = int(s0 + 0.001); | 1239 int s0i = int(s0 + 0.001); |
1387 max = RealTime::frame2RealTime(w1, m_model->getSampleRate()); | 1248 max = RealTime::frame2RealTime(w1, m_model->getSampleRate()); |
1388 return true; | 1249 return true; |
1389 } | 1250 } |
1390 | 1251 |
1391 bool | 1252 bool |
1392 SpectrogramLayer::getYBinSourceRange(View *v, int y, double &freqMin, double &freqMax) | 1253 SpectrogramLayer::getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) |
1393 const | 1254 const |
1394 { | 1255 { |
1395 double q0 = 0, q1 = 0; | 1256 double q0 = 0, q1 = 0; |
1396 if (!getYBinRange(v, y, q0, q1)) return false; | 1257 if (!getYBinRange(v, y, q0, q1)) return false; |
1397 | 1258 |
1406 } | 1267 } |
1407 return true; | 1268 return true; |
1408 } | 1269 } |
1409 | 1270 |
1410 bool | 1271 bool |
1411 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, | 1272 SpectrogramLayer::getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, |
1412 double &freqMin, double &freqMax, | 1273 double &freqMin, double &freqMax, |
1413 double &adjFreqMin, double &adjFreqMax) | 1274 double &adjFreqMin, double &adjFreqMax) |
1414 const | 1275 const |
1415 { | 1276 { |
1416 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1277 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1440 m_binDisplay == PeakFrequencies); | 1301 m_binDisplay == PeakFrequencies); |
1441 | 1302 |
1442 for (int q = q0i; q <= q1i; ++q) { | 1303 for (int q = q0i; q <= q1i; ++q) { |
1443 | 1304 |
1444 for (int s = s0i; s <= s1i; ++s) { | 1305 for (int s = s0i; s <= s1i; ++s) { |
1445 | |
1446 if (!fft->isColumnAvailable(s)) continue; | |
1447 | 1306 |
1448 double binfreq = (double(sr) * q) / m_windowSize; | 1307 double binfreq = (double(sr) * q) / m_windowSize; |
1449 if (q == q0i) freqMin = binfreq; | 1308 if (q == q0i) freqMin = binfreq; |
1450 if (q == q1i) freqMax = binfreq; | 1309 if (q == q1i) freqMax = binfreq; |
1451 | 1310 |
1473 | 1332 |
1474 return haveAdj; | 1333 return haveAdj; |
1475 } | 1334 } |
1476 | 1335 |
1477 bool | 1336 bool |
1478 SpectrogramLayer::getXYBinSourceRange(View *v, int x, int y, | 1337 SpectrogramLayer::getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, |
1479 double &min, double &max, | 1338 double &min, double &max, |
1480 double &phaseMin, double &phaseMax) const | 1339 double &phaseMin, double &phaseMax) const |
1481 { | 1340 { |
1482 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1341 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1483 return false; | 1342 return false; |
1516 | 1375 |
1517 for (int q = q0i; q <= q1i; ++q) { | 1376 for (int q = q0i; q <= q1i; ++q) { |
1518 for (int s = s0i; s <= s1i; ++s) { | 1377 for (int s = s0i; s <= s1i; ++s) { |
1519 if (s >= 0 && q >= 0 && s < cw && q < ch) { | 1378 if (s >= 0 && q >= 0 && s < cw && q < ch) { |
1520 | 1379 |
1521 if (!fft->isColumnAvailable(s)) continue; | |
1522 | |
1523 double value; | 1380 double value; |
1524 | 1381 |
1525 value = fft->getPhaseAt(s, q); | 1382 value = fft->getPhaseAt(s, q); |
1526 if (!have || value < phaseMin) { phaseMin = value; } | 1383 if (!have || value < phaseMin) { phaseMin = value; } |
1527 if (!have || value > phaseMax) { phaseMax = value; } | 1384 if (!have || value > phaseMax) { phaseMax = value; } |
1542 | 1399 |
1543 return rv; | 1400 return rv; |
1544 } | 1401 } |
1545 | 1402 |
1546 int | 1403 int |
1547 SpectrogramLayer::getZeroPadLevel(const View *v) const | 1404 SpectrogramLayer::getZeroPadLevel(const LayerGeometryProvider *v) const |
1548 { | 1405 { |
1549 //!!! tidy all this stuff | 1406 //!!! tidy all this stuff |
1550 | 1407 |
1551 if (m_binDisplay != AllBins) return 0; | 1408 if (m_binDisplay != AllBins) return 0; |
1552 | 1409 |
1572 if (minbin < 1) minbin = 1; | 1429 if (minbin < 1) minbin = 1; |
1573 if (minbin >= maxbin) minbin = maxbin - 1; | 1430 if (minbin >= maxbin) minbin = maxbin - 1; |
1574 } | 1431 } |
1575 | 1432 |
1576 double perPixel = | 1433 double perPixel = |
1577 double(v->height()) / | 1434 double(v->getPaintHeight()) / |
1578 double((maxbin - minbin) / (m_zeroPadLevel + 1)); | 1435 double((maxbin - minbin) / (m_zeroPadLevel + 1)); |
1579 | 1436 |
1580 if (perPixel > 2.8) { | 1437 if (perPixel > 2.8) { |
1581 return 3; // 4x oversampling | 1438 return 3; // 4x oversampling |
1582 } else if (perPixel > 1.5) { | 1439 } else if (perPixel > 1.5) { |
1585 return 0; // 1x | 1442 return 0; // 1x |
1586 } | 1443 } |
1587 } | 1444 } |
1588 | 1445 |
1589 int | 1446 int |
1590 SpectrogramLayer::getFFTSize(const View *v) const | 1447 SpectrogramLayer::getFFTSize(const LayerGeometryProvider *v) const |
1591 { | 1448 { |
1592 return m_fftSize * (getZeroPadLevel(v) + 1); | 1449 return m_fftSize * (getZeroPadLevel(v) + 1); |
1593 } | 1450 } |
1594 | 1451 |
1595 FFTModel * | 1452 FFTModel * |
1596 SpectrogramLayer::getFFTModel(const View *v) const | 1453 SpectrogramLayer::getFFTModel(const LayerGeometryProvider *v) const |
1597 { | 1454 { |
1598 if (!m_model) return 0; | 1455 if (!m_model) return 0; |
1599 | 1456 |
1600 int fftSize = getFFTSize(v); | 1457 int fftSize = getFFTSize(v); |
1601 | 1458 |
1602 if (m_fftModels.find(v) != m_fftModels.end()) { | 1459 const View *view = v->getView(); |
1603 if (m_fftModels[v].first == 0) { | 1460 |
1604 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1461 if (m_fftModels.find(view->getId()) != m_fftModels.end()) { |
1605 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found null model" << endl; | 1462 if (m_fftModels[view->getId()] == 0) { |
1463 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1464 cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found null model" << endl; | |
1606 #endif | 1465 #endif |
1607 return 0; | 1466 return 0; |
1608 } | 1467 } |
1609 if (m_fftModels[v].first->getHeight() != fftSize / 2 + 1) { | 1468 if (m_fftModels[view->getId()]->getHeight() != fftSize / 2 + 1) { |
1610 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1469 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1611 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a model with the wrong height (" << m_fftModels[v].first->getHeight() << ", wanted " << (fftSize / 2 + 1) << ")" << endl; | 1470 cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a model with the wrong height (" << m_fftModels[view->getId()]->getHeight() << ", wanted " << (fftSize / 2 + 1) << ")" << endl; |
1612 #endif | 1471 #endif |
1613 delete m_fftModels[v].first; | 1472 delete m_fftModels[view->getId()]; |
1614 m_fftModels.erase(v); | 1473 m_fftModels.erase(view->getId()); |
1615 delete m_peakCaches[v]; | 1474 delete m_peakCaches[view->getId()]; |
1616 m_peakCaches.erase(v); | 1475 m_peakCaches.erase(view->getId()); |
1617 } else { | 1476 } else { |
1618 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1477 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1619 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[v].first->getHeight() << endl; | 1478 cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[view->getId()]->getHeight() << endl; |
1620 #endif | 1479 #endif |
1621 return m_fftModels[v].first; | 1480 return m_fftModels[view->getId()]; |
1622 } | 1481 } |
1623 } | 1482 } |
1624 | 1483 |
1625 if (m_fftModels.find(v) == m_fftModels.end()) { | 1484 if (m_fftModels.find(view->getId()) == m_fftModels.end()) { |
1626 | 1485 |
1627 FFTModel *model = new FFTModel(m_model, | 1486 FFTModel *model = new FFTModel(m_model, |
1628 m_channel, | 1487 m_channel, |
1629 m_windowType, | 1488 m_windowType, |
1630 m_windowSize, | 1489 m_windowSize, |
1635 QMessageBox::critical | 1494 QMessageBox::critical |
1636 (0, tr("FFT cache failed"), | 1495 (0, tr("FFT cache failed"), |
1637 tr("Failed to create the FFT model for this spectrogram.\n" | 1496 tr("Failed to create the FFT model for this spectrogram.\n" |
1638 "There may be insufficient memory or disc space to continue.")); | 1497 "There may be insufficient memory or disc space to continue.")); |
1639 delete model; | 1498 delete model; |
1640 m_fftModels[v] = FFTFillPair(0, 0); | 1499 m_fftModels[view->getId()] = 0; |
1641 return 0; | 1500 return 0; |
1642 } | 1501 } |
1643 | 1502 |
1644 if (!m_sliceableModel) { | 1503 if (!m_sliceableModel) { |
1645 #ifdef DEBUG_SPECTROGRAM | 1504 #ifdef DEBUG_SPECTROGRAM |
1647 #endif | 1506 #endif |
1648 ((SpectrogramLayer *)this)->sliceableModelReplaced(0, model); | 1507 ((SpectrogramLayer *)this)->sliceableModelReplaced(0, model); |
1649 m_sliceableModel = model; | 1508 m_sliceableModel = model; |
1650 } | 1509 } |
1651 | 1510 |
1652 m_fftModels[v] = FFTFillPair(model, 0); | 1511 m_fftModels[view->getId()] = model; |
1653 | 1512 } |
1654 delete m_updateTimer; | 1513 |
1655 m_updateTimer = new QTimer((SpectrogramLayer *)this); | 1514 return m_fftModels[view->getId()]; |
1656 connect(m_updateTimer, SIGNAL(timeout()), | |
1657 this, SLOT(fillTimerTimedOut())); | |
1658 m_updateTimer->start(200); | |
1659 } | |
1660 | |
1661 return m_fftModels[v].first; | |
1662 } | 1515 } |
1663 | 1516 |
1664 Dense3DModelPeakCache * | 1517 Dense3DModelPeakCache * |
1665 SpectrogramLayer::getPeakCache(const View *v) const | 1518 SpectrogramLayer::getPeakCache(const LayerGeometryProvider *v) const |
1666 { | 1519 { |
1667 if (!m_peakCaches[v]) { | 1520 const View *view = v->getView(); |
1521 if (!m_peakCaches[view->getId()]) { | |
1668 FFTModel *f = getFFTModel(v); | 1522 FFTModel *f = getFFTModel(v); |
1669 if (!f) return 0; | 1523 if (!f) return 0; |
1670 m_peakCaches[v] = new Dense3DModelPeakCache(f, 8); | 1524 m_peakCaches[view->getId()] = new Dense3DModelPeakCache(f, 8); |
1671 } | 1525 } |
1672 return m_peakCaches[v]; | 1526 return m_peakCaches[view->getId()]; |
1673 } | 1527 } |
1674 | 1528 |
1675 const Model * | 1529 const Model * |
1676 SpectrogramLayer::getSliceableModel() const | 1530 SpectrogramLayer::getSliceableModel() const |
1677 { | 1531 { |
1678 if (m_sliceableModel) return m_sliceableModel; | 1532 if (m_sliceableModel) return m_sliceableModel; |
1679 if (m_fftModels.empty()) return 0; | 1533 if (m_fftModels.empty()) return 0; |
1680 m_sliceableModel = m_fftModels.begin()->second.first; | 1534 m_sliceableModel = m_fftModels.begin()->second; |
1681 return m_sliceableModel; | 1535 return m_sliceableModel; |
1682 } | 1536 } |
1683 | 1537 |
1684 void | 1538 void |
1685 SpectrogramLayer::invalidateFFTModels() | 1539 SpectrogramLayer::invalidateFFTModels() |
1686 { | 1540 { |
1541 #ifdef DEBUG_SPECTROGRAM | |
1542 cerr << "SpectrogramLayer::invalidateFFTModels called" << endl; | |
1543 #endif | |
1687 for (ViewFFTMap::iterator i = m_fftModels.begin(); | 1544 for (ViewFFTMap::iterator i = m_fftModels.begin(); |
1688 i != m_fftModels.end(); ++i) { | 1545 i != m_fftModels.end(); ++i) { |
1689 delete i->second.first; | 1546 delete i->second; |
1690 } | 1547 } |
1691 for (PeakCacheMap::iterator i = m_peakCaches.begin(); | 1548 for (PeakCacheMap::iterator i = m_peakCaches.begin(); |
1692 i != m_peakCaches.end(); ++i) { | 1549 i != m_peakCaches.end(); ++i) { |
1693 delete i->second; | 1550 delete i->second; |
1694 } | 1551 } |
1704 } | 1561 } |
1705 | 1562 |
1706 void | 1563 void |
1707 SpectrogramLayer::invalidateMagnitudes() | 1564 SpectrogramLayer::invalidateMagnitudes() |
1708 { | 1565 { |
1566 #ifdef DEBUG_SPECTROGRAM | |
1567 cerr << "SpectrogramLayer::invalidateMagnitudes called" << endl; | |
1568 #endif | |
1709 m_viewMags.clear(); | 1569 m_viewMags.clear(); |
1710 for (std::vector<MagnitudeRange>::iterator i = m_columnMags.begin(); | 1570 for (vector<MagnitudeRange>::iterator i = m_columnMags.begin(); |
1711 i != m_columnMags.end(); ++i) { | 1571 i != m_columnMags.end(); ++i) { |
1712 *i = MagnitudeRange(); | 1572 *i = MagnitudeRange(); |
1713 } | 1573 } |
1714 } | 1574 } |
1715 | 1575 |
1716 bool | 1576 bool |
1717 SpectrogramLayer::updateViewMagnitudes(View *v) const | 1577 SpectrogramLayer::updateViewMagnitudes(LayerGeometryProvider *v) const |
1718 { | 1578 { |
1719 MagnitudeRange mag; | 1579 MagnitudeRange mag; |
1720 | 1580 |
1721 int x0 = 0, x1 = v->width(); | 1581 int x0 = 0, x1 = v->getPaintWidth(); |
1722 double s00 = 0, s01 = 0, s10 = 0, s11 = 0; | 1582 double s00 = 0, s01 = 0, s10 = 0, s11 = 0; |
1723 | 1583 |
1724 if (!getXBinRange(v, x0, s00, s01)) { | 1584 if (!getXBinRange(v, x0, s00, s01)) { |
1725 s00 = s01 = double(m_model->getStartFrame()) / getWindowIncrement(); | 1585 s00 = s01 = double(m_model->getStartFrame()) / getWindowIncrement(); |
1726 } | 1586 } |
1727 | 1587 |
1728 if (!getXBinRange(v, x1, s10, s11)) { | 1588 if (!getXBinRange(v, x1, s10, s11)) { |
1729 s10 = s11 = double(m_model->getEndFrame()) / getWindowIncrement(); | 1589 s10 = s11 = double(m_model->getEndFrame()) / getWindowIncrement(); |
1730 } | 1590 } |
1731 | 1591 |
1732 int s0 = int(std::min(s00, s10) + 0.0001); | 1592 int s0 = int(min(s00, s10) + 0.0001); |
1733 int s1 = int(std::max(s01, s11) + 0.0001); | 1593 int s1 = int(max(s01, s11) + 0.0001); |
1734 | 1594 |
1735 // SVDEBUG << "SpectrogramLayer::updateViewMagnitudes: x0 = " << x0 << ", x1 = " << x1 << ", s00 = " << s00 << ", s11 = " << s11 << " s0 = " << s0 << ", s1 = " << s1 << endl; | 1595 // SVDEBUG << "SpectrogramLayer::updateViewMagnitudes: x0 = " << x0 << ", x1 = " << x1 << ", s00 = " << s00 << ", s11 = " << s11 << " s0 = " << s0 << ", s1 = " << s1 << endl; |
1736 | 1596 |
1737 if (int(m_columnMags.size()) <= s1) { | 1597 if (int(m_columnMags.size()) <= s1) { |
1738 m_columnMags.resize(s1 + 1); | 1598 m_columnMags.resize(s1 + 1); |
1743 mag.sample(m_columnMags[s]); | 1603 mag.sample(m_columnMags[s]); |
1744 } | 1604 } |
1745 } | 1605 } |
1746 | 1606 |
1747 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1607 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1748 SVDEBUG << "SpectrogramLayer::updateViewMagnitudes returning from cols " | 1608 cerr << "SpectrogramLayer::updateViewMagnitudes returning from cols " |
1749 << s0 << " -> " << s1 << " inclusive" << endl; | 1609 << s0 << " -> " << s1 << " inclusive" << endl; |
1610 cerr << "SpectrogramLayer::updateViewMagnitudes: for view id " << v->getId() | |
1611 << ": min is " << mag.getMin() << ", max is " << mag.getMax() << endl; | |
1750 #endif | 1612 #endif |
1751 | 1613 |
1752 if (!mag.isSet()) return false; | 1614 if (!mag.isSet()) return false; |
1753 if (mag == m_viewMags[v]) return false; | 1615 if (mag == m_viewMags[v->getId()]) return false; |
1754 m_viewMags[v] = mag; | 1616 m_viewMags[v->getId()] = mag; |
1755 return true; | 1617 return true; |
1756 } | 1618 } |
1757 | 1619 |
1758 void | 1620 void |
1759 SpectrogramLayer::setSynchronousPainting(bool synchronous) | 1621 SpectrogramLayer::setSynchronousPainting(bool synchronous) |
1760 { | 1622 { |
1761 m_synchronous = synchronous; | 1623 m_synchronous = synchronous; |
1762 } | 1624 } |
1763 | 1625 |
1626 ScrollableImageCache & | |
1627 SpectrogramLayer::getImageCacheReference(const LayerGeometryProvider *view) const | |
1628 { | |
1629 if (m_imageCaches.find(view->getId()) == m_imageCaches.end()) { | |
1630 m_imageCaches[view->getId()] = ScrollableImageCache(view); | |
1631 } | |
1632 return m_imageCaches.at(view->getId()); | |
1633 } | |
1634 | |
1764 void | 1635 void |
1765 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const | 1636 SpectrogramLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const |
1766 { | 1637 { |
1767 // What a lovely, old-fashioned function this is. | |
1768 // It's practically FORTRAN 77 in its clarity and linearity. | |
1769 | |
1770 Profiler profiler("SpectrogramLayer::paint", false); | 1638 Profiler profiler("SpectrogramLayer::paint", false); |
1771 | 1639 |
1772 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1640 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1773 SVDEBUG << "SpectrogramLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << endl; | 1641 cerr << "SpectrogramLayer::paint() entering: m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << endl; |
1774 | 1642 |
1775 cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; | 1643 cerr << "SpectrogramLayer::paint(): rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; |
1776 #endif | 1644 #endif |
1777 | 1645 |
1778 sv_frame_t startFrame = v->getStartFrame(); | 1646 sv_frame_t startFrame = v->getStartFrame(); |
1779 if (startFrame < 0) m_candidateFillStartFrame = 0; | |
1780 else m_candidateFillStartFrame = startFrame; | |
1781 | 1647 |
1782 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1648 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1783 return; | 1649 return; |
1784 } | 1650 } |
1785 | 1651 |
1793 // in the cache-fill thread above. | 1659 // in the cache-fill thread above. |
1794 //!!! no inter use cache-fill thread | 1660 //!!! no inter use cache-fill thread |
1795 const_cast<SpectrogramLayer *>(this)->Layer::setLayerDormant(v, false); | 1661 const_cast<SpectrogramLayer *>(this)->Layer::setLayerDormant(v, false); |
1796 | 1662 |
1797 int fftSize = getFFTSize(v); | 1663 int fftSize = getFFTSize(v); |
1798 /* | 1664 |
1799 FFTModel *fft = getFFTModel(v); | 1665 const View *view = v->getView(); |
1800 if (!fft) { | 1666 ScrollableImageCache &cache = getImageCacheReference(view); |
1801 cerr << "ERROR: SpectrogramLayer::paint(): No FFT model, returning" << endl; | 1667 |
1802 return; | 1668 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1803 } | 1669 cerr << "SpectrogramLayer::paint(): image cache valid area from " << cache.getValidLeft() << " width " << cache.getValidWidth() << ", height " << cache.getSize().height() << endl; |
1804 */ | 1670 if (rect.x() + rect.width() + 1 < cache.getValidLeft() || |
1805 ImageCache &cache = m_imageCaches[v]; | 1671 rect.x() > cache.getValidRight()) { |
1806 | 1672 cerr << "SpectrogramLayer: NOTE: requested rect is not contiguous with cache valid area" << endl; |
1807 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1673 } |
1808 SVDEBUG << "SpectrogramLayer::paint(): image cache valid area " << cache. | |
1809 | |
1810 validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << endl; | |
1811 #endif | |
1812 | |
1813 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1814 bool stillCacheing = (m_updateTimer != 0); | |
1815 SVDEBUG << "SpectrogramLayer::paint(): Still cacheing = " << stillCacheing << endl; | |
1816 #endif | 1674 #endif |
1817 | 1675 |
1818 int zoomLevel = v->getZoomLevel(); | 1676 int zoomLevel = v->getZoomLevel(); |
1819 | 1677 |
1820 int x0 = 0; | 1678 int x0 = v->getXForViewX(rect.x()); |
1821 int x1 = v->width(); | 1679 int x1 = v->getXForViewX(rect.x() + rect.width()); |
1822 | 1680 if (x0 < 0) x0 = 0; |
1823 bool recreateWholeImageCache = true; | 1681 if (x1 > v->getPaintWidth()) x1 = v->getPaintWidth(); |
1824 | 1682 |
1825 x0 = rect.left(); | 1683 if (updateViewMagnitudes(v)) { |
1826 x1 = rect.right() + 1; | 1684 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1827 /* | 1685 cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v->getId()].getMin() << "->" << m_viewMags[v->getId()].getMax() << "]" << endl; |
1828 double xPixelRatio = double(fft->getResolution()) / double(zoomLevel); | 1686 #endif |
1829 cerr << "xPixelRatio = " << xPixelRatio << endl; | 1687 if (m_normalization == NormalizeVisibleArea) { |
1830 if (xPixelRatio < 1.f) xPixelRatio = 1.f; | 1688 cache.invalidate(); |
1831 */ | 1689 } |
1832 if (cache.validArea.width() > 0) { | 1690 } |
1833 | 1691 |
1834 int cw = cache.image.width(); | 1692 if (cache.getZoomLevel() != zoomLevel || |
1835 int ch = cache.image.height(); | 1693 cache.getSize() != v->getPaintSize()) { |
1694 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1695 cerr << "SpectrogramLayer: resizing image cache from " | |
1696 << cache.getSize().width() << "x" << cache.getSize().height() | |
1697 << " to " | |
1698 << v->getPaintSize().width() << "x" << v->getPaintSize().height() | |
1699 << " and updating zoom level from " << cache.getZoomLevel() | |
1700 << " to " << zoomLevel | |
1701 << endl; | |
1702 #endif | |
1703 cache.resize(v->getPaintSize()); | |
1704 cache.setZoomLevel(zoomLevel); | |
1705 cache.setStartFrame(startFrame); | |
1706 } | |
1707 | |
1708 if (cache.isValid()) { | |
1836 | 1709 |
1837 if (int(cache.zoomLevel) == zoomLevel && | 1710 if (v->getXForFrame(cache.getStartFrame()) == |
1838 cw == v->width() && | 1711 v->getXForFrame(startFrame) && |
1839 ch == v->height()) { | 1712 cache.getValidLeft() <= x0 && |
1840 | 1713 cache.getValidRight() >= x1) { |
1841 if (v->getXForFrame(cache.startFrame) == | 1714 |
1842 v->getXForFrame(startFrame) && | 1715 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1843 cache.validArea.x() <= x0 && | 1716 cerr << "SpectrogramLayer: image cache hit!" << endl; |
1844 cache.validArea.x() + cache.validArea.width() >= x1) { | 1717 #endif |
1845 | 1718 |
1846 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1719 paint.drawImage(rect, cache.getImage(), rect); |
1847 cerr << "SpectrogramLayer: image cache good" << endl; | 1720 |
1848 #endif | 1721 illuminateLocalFeatures(v, paint); |
1849 | 1722 return; |
1850 paint.drawImage(rect, cache.image, rect); | 1723 |
1851 //!!! | 1724 } else { |
1852 // paint.drawImage(v->rect(), cache.image, | 1725 |
1853 // QRect(QPoint(0, 0), cache.image.size())); | 1726 // cache doesn't begin at the right frame or doesn't |
1854 | 1727 // contain the complete view, but might be scrollable or |
1855 illuminateLocalFeatures(v, paint); | 1728 // partially usable |
1856 return; | 1729 |
1857 | 1730 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1858 } else { | 1731 cerr << "SpectrogramLayer: scrolling the image cache if applicable" << endl; |
1859 | 1732 #endif |
1860 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1733 |
1861 cerr << "SpectrogramLayer: image cache partially OK" << endl; | 1734 cache.scrollTo(startFrame); |
1862 #endif | 1735 |
1863 | 1736 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1864 recreateWholeImageCache = false; | 1737 cerr << "SpectrogramLayer: after scrolling, cache valid from " |
1865 | 1738 << cache.getValidLeft() << " width " << cache.getValidWidth() |
1866 int dx = v->getXForFrame(cache.startFrame) - | 1739 << endl; |
1867 v->getXForFrame(startFrame); | 1740 #endif |
1868 | 1741 } |
1869 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1742 } |
1870 cerr << "SpectrogramLayer: dx = " << dx << " (image cache " << cw << "x" << ch << ")" << endl; | 1743 |
1871 #endif | 1744 bool rightToLeft = false; |
1872 | 1745 |
1873 if (dx != 0 && | 1746 if (!cache.isValid()) { |
1874 dx > -cw && | 1747 if (!m_synchronous) { |
1875 dx < cw) { | 1748 // When rendering the whole thing, start from somewhere near |
1876 | 1749 // the middle so that the region of interest appears first |
1877 int dxp = dx; | 1750 |
1878 if (dxp < 0) dxp = -dxp; | 1751 //!!! (perhaps we should have some cunning test to avoid |
1879 size_t copy = (cw - dxp) * sizeof(QRgb); | 1752 //!!! doing this if past repaints have appeared fast |
1880 for (int y = 0; y < ch; ++y) { | 1753 //!!! enough to do the whole width in one shot) |
1881 QRgb *line = (QRgb *)cache.image.scanLine(y); | 1754 if (x0 == 0 && x1 == v->getPaintWidth()) { |
1882 if (dx < 0) { | 1755 x0 = int(x1 * 0.3); |
1883 memmove(line, line + dxp, copy); | |
1884 } else { | |
1885 memmove(line + dxp, line, copy); | |
1886 } | |
1887 } | |
1888 | |
1889 int px = cache.validArea.x(); | |
1890 int pw = cache.validArea.width(); | |
1891 | |
1892 if (dx < 0) { | |
1893 x0 = cw + dx; | |
1894 x1 = cw; | |
1895 px += dx; | |
1896 if (px < 0) { | |
1897 pw += px; | |
1898 px = 0; | |
1899 if (pw < 0) pw = 0; | |
1900 } | |
1901 } else { | |
1902 x0 = 0; | |
1903 x1 = dx; | |
1904 px += dx; | |
1905 if (px + pw > cw) { | |
1906 pw = int(cw) - px; | |
1907 if (pw < 0) pw = 0; | |
1908 } | |
1909 } | |
1910 | |
1911 cache.validArea = | |
1912 QRect(px, cache.validArea.y(), | |
1913 pw, cache.validArea.height()); | |
1914 | |
1915 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1916 cerr << "valid area now " | |
1917 << px << "," << cache.validArea.y() | |
1918 << " " << pw << "x" << cache.validArea.height() | |
1919 << endl; | |
1920 #endif | |
1921 /* | |
1922 paint.drawImage(rect & cache.validArea, | |
1923 cache.image, | |
1924 rect & cache.validArea); | |
1925 */ | |
1926 } else if (dx != 0) { | |
1927 | |
1928 // we scrolled too far to be of use | |
1929 | |
1930 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1931 cerr << "dx == " << dx << ": scrolled too far for cache to be useful" << endl; | |
1932 #endif | |
1933 | |
1934 cache.validArea = QRect(); | |
1935 recreateWholeImageCache = true; | |
1936 } | |
1937 } | |
1938 } else { | |
1939 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1940 cerr << "SpectrogramLayer: image cache useless" << endl; | |
1941 if (int(cache.zoomLevel) != zoomLevel) { | |
1942 cerr << "(cache zoomLevel " << cache.zoomLevel | |
1943 << " != " << zoomLevel << ")" << endl; | |
1944 } | 1756 } |
1945 if (cw != v->width()) { | |
1946 cerr << "(cache width " << cw | |
1947 << " != " << v->width(); | |
1948 } | |
1949 if (ch != v->height()) { | |
1950 cerr << "(cache height " << ch | |
1951 << " != " << v->height(); | |
1952 } | |
1953 #endif | |
1954 cache.validArea = QRect(); | |
1955 // recreateWholeImageCache = true; | |
1956 } | |
1957 } | |
1958 | |
1959 if (updateViewMagnitudes(v)) { | |
1960 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1961 cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << endl; | |
1962 #endif | |
1963 if (m_normalizeVisibleArea) { | |
1964 cache.validArea = QRect(); | |
1965 recreateWholeImageCache = true; | |
1966 } | 1757 } |
1967 } else { | 1758 } else { |
1968 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1759 // When rendering only a part of the cache, we need to make |
1969 cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << endl; | 1760 // sure that the part we're rendering is adjacent to (or |
1970 #endif | 1761 // overlapping) a valid area of cache, if we have one. The |
1971 } | 1762 // alternative is to ditch the valid area of cache and render |
1972 | 1763 // only the requested area, but that's risky because this can |
1973 if (recreateWholeImageCache) { | 1764 // happen when just waving the pointer over a small part of |
1974 x0 = 0; | 1765 // the view -- if we lose the partly-built cache every time |
1975 x1 = v->width(); | 1766 // the user does that, we'll never finish building it. |
1976 } | 1767 int left = x0; |
1977 | 1768 int width = x1 - x0; |
1978 struct timeval tv; | 1769 bool isLeftOfValidArea = false; |
1979 (void)gettimeofday(&tv, 0); | 1770 cache.adjustToTouchValidArea(left, width, isLeftOfValidArea); |
1980 RealTime mainPaintStart = RealTime::fromTimeval(tv); | 1771 x0 = left; |
1981 | 1772 x1 = x0 + width; |
1982 int paintBlockWidth = m_lastPaintBlockWidth; | 1773 |
1983 | 1774 // That call also told us whether we should be painting |
1984 if (m_synchronous) { | 1775 // sub-regions of our target region in right-to-left order in |
1985 if (paintBlockWidth < x1 - x0) { | 1776 // order to ensure contiguity |
1986 // always paint full width | 1777 rightToLeft = isLeftOfValidArea; |
1987 paintBlockWidth = x1 - x0; | 1778 } |
1988 } | 1779 |
1989 } else { | |
1990 if (paintBlockWidth == 0) { | |
1991 paintBlockWidth = (300000 / zoomLevel); | |
1992 } else { | |
1993 RealTime lastTime = m_lastPaintTime; | |
1994 while (lastTime > RealTime::fromMilliseconds(200) && | |
1995 paintBlockWidth > 50) { | |
1996 paintBlockWidth /= 2; | |
1997 lastTime = lastTime / 2; | |
1998 } | |
1999 while (lastTime < RealTime::fromMilliseconds(90) && | |
2000 paintBlockWidth < 1500) { | |
2001 paintBlockWidth *= 2; | |
2002 lastTime = lastTime * 2; | |
2003 } | |
2004 } | |
2005 | |
2006 if (paintBlockWidth < 20) paintBlockWidth = 20; | |
2007 } | |
2008 | |
2009 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2010 cerr << "[" << this << "]: last paint width: " << m_lastPaintBlockWidth << ", last paint time: " << m_lastPaintTime << ", new paint width: " << paintBlockWidth << endl; | |
2011 #endif | |
2012 | |
2013 // We always paint the full height when refreshing the cache. | 1780 // We always paint the full height when refreshing the cache. |
2014 // Smaller heights can be used when painting direct from cache | 1781 // Smaller heights can be used when painting direct from cache |
2015 // (further up in this function), but we want to ensure the cache | 1782 // (further up in this function), but we want to ensure the cache |
2016 // is coherent without having to worry about vertical matching of | 1783 // is coherent without having to worry about vertical matching of |
2017 // required and valid areas as well as horizontal. | 1784 // required and valid areas as well as horizontal. |
2018 | 1785 int h = v->getPaintHeight(); |
2019 int h = v->height(); | 1786 |
2020 | 1787 int repaintWidth = x1 - x0; |
2021 if (cache.validArea.width() > 0) { | 1788 |
2022 | 1789 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2023 // If part of the cache is known to be valid, select a strip | 1790 cerr << "SpectrogramLayer: x0 " << x0 << ", x1 " << x1 |
2024 // immediately to left or right of the valid part | 1791 << ", repaintWidth " << repaintWidth << ", h " << h |
2025 | 1792 << ", rightToLeft " << rightToLeft << endl; |
2026 //!!! this really needs to be coordinated with the selection | |
2027 //!!! of m_drawBuffer boundaries in the bufferBinResolution | |
2028 //!!! case below | |
2029 | |
2030 int vx0 = 0, vx1 = 0; | |
2031 vx0 = cache.validArea.x(); | |
2032 vx1 = cache.validArea.x() + cache.validArea.width(); | |
2033 | |
2034 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2035 cerr << "x0 " << x0 << ", x1 " << x1 << ", vx0 " << vx0 << ", vx1 " << vx1 << ", paintBlockWidth " << paintBlockWidth << endl; | |
2036 #endif | |
2037 if (x0 < vx0) { | |
2038 if (x0 + paintBlockWidth < vx0) { | |
2039 x0 = vx0 - paintBlockWidth; | |
2040 } | |
2041 x1 = vx0; | |
2042 } else if (x0 >= vx1) { | |
2043 x0 = vx1; | |
2044 if (x1 > x0 + paintBlockWidth) { | |
2045 x1 = x0 + paintBlockWidth; | |
2046 } | |
2047 } else { | |
2048 // x0 is within the valid area | |
2049 if (x1 > vx1) { | |
2050 x0 = vx1; | |
2051 if (x0 + paintBlockWidth < x1) { | |
2052 x1 = x0 + paintBlockWidth; | |
2053 } | |
2054 } else { | |
2055 x1 = x0; // it's all valid, paint nothing | |
2056 } | |
2057 } | |
2058 | |
2059 cache.validArea = QRect | |
2060 (std::min(vx0, x0), cache.validArea.y(), | |
2061 std::max(vx1 - std::min(vx0, x0), | |
2062 x1 - std::min(vx0, x0)), | |
2063 cache.validArea.height()); | |
2064 | |
2065 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2066 cerr << "Valid area becomes " << cache.validArea.x() | |
2067 << ", " << cache.validArea.y() << ", " | |
2068 << cache.validArea.width() << "x" | |
2069 << cache.validArea.height() << endl; | |
2070 #endif | |
2071 | |
2072 } else { | |
2073 if (x1 > x0 + paintBlockWidth) { | |
2074 int sfx = x1; | |
2075 if (startFrame < 0) sfx = v->getXForFrame(0); | |
2076 if (sfx >= x0 && sfx + paintBlockWidth <= x1) { | |
2077 x0 = sfx; | |
2078 x1 = x0 + paintBlockWidth; | |
2079 } else { | |
2080 int mid = (x1 + x0) / 2; | |
2081 x0 = mid - paintBlockWidth/2; | |
2082 x1 = x0 + paintBlockWidth; | |
2083 } | |
2084 } | |
2085 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2086 cerr << "Valid area becomes " << x0 << ", 0, " << (x1-x0) | |
2087 << "x" << h << endl; | |
2088 #endif | |
2089 cache.validArea = QRect(x0, 0, x1 - x0, h); | |
2090 } | |
2091 | |
2092 /* | |
2093 if (xPixelRatio != 1.f) { | |
2094 x0 = int((int(x0 / xPixelRatio) - 4) * xPixelRatio + 0.0001); | |
2095 x1 = int((int(x1 / xPixelRatio) + 4) * xPixelRatio + 0.0001); | |
2096 } | |
2097 */ | |
2098 int w = x1 - x0; | |
2099 | |
2100 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2101 cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << endl; | |
2102 #endif | 1793 #endif |
2103 | 1794 |
2104 sv_samplerate_t sr = m_model->getSampleRate(); | 1795 sv_samplerate_t sr = m_model->getSampleRate(); |
2105 | 1796 |
2106 // Set minFreq and maxFreq to the frequency extents of the possibly | 1797 // Set minFreq and maxFreq to the frequency extents of the possibly |
2146 // cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << endl; | 1837 // cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << endl; |
2147 | 1838 |
2148 int increment = getWindowIncrement(); | 1839 int increment = getWindowIncrement(); |
2149 | 1840 |
2150 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 1841 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
2151 /* | 1842 |
2152 double yforbin[maxbin - minbin + 1]; | 1843 MagnitudeRange overallMag = m_viewMags[v->getId()]; |
2153 | |
2154 for (int q = minbin; q <= maxbin; ++q) { | |
2155 double f0 = (double(q) * sr) / fftSize; | |
2156 yforbin[q - minbin] = | |
2157 v->getYForFrequency(f0, displayMinFreq, displayMaxFreq, | |
2158 logarithmic); | |
2159 } | |
2160 */ | |
2161 MagnitudeRange overallMag = m_viewMags[v]; | |
2162 bool overallMagChanged = false; | 1844 bool overallMagChanged = false; |
2163 | 1845 |
2164 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1846 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2165 cerr << ((double(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << endl; | 1847 cerr << "SpectrogramLayer: " << ((double(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << endl; |
2166 #endif | 1848 #endif |
2167 | 1849 |
2168 if (w == 0) { | 1850 if (repaintWidth == 0) { |
2169 SVDEBUG << "*** NOTE: w == 0" << endl; | 1851 SVDEBUG << "*** NOTE: repaintWidth == 0" << endl; |
2170 } | 1852 } |
2171 | |
2172 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2173 int pixels = 0; | |
2174 #endif | |
2175 | 1853 |
2176 Profiler outerprof("SpectrogramLayer::paint: all cols"); | 1854 Profiler outerprof("SpectrogramLayer::paint: all cols"); |
2177 | 1855 |
2178 // The draw buffer contains a fragment at either our pixel | 1856 // The draw buffer contains a fragment at either our pixel |
2179 // resolution (if there is more than one time-bin per pixel) or | 1857 // resolution (if there is more than one time-bin per pixel) or |
2186 // If (getFrameForX(x) / increment) * increment == | 1864 // If (getFrameForX(x) / increment) * increment == |
2187 // getFrameForX(x), then x is a time-bin boundary. We want two | 1865 // getFrameForX(x), then x is a time-bin boundary. We want two |
2188 // such boundaries at either side of the draw buffer -- one which | 1866 // such boundaries at either side of the draw buffer -- one which |
2189 // we draw up to, and one which we subsequently crop at. | 1867 // we draw up to, and one which we subsequently crop at. |
2190 | 1868 |
2191 bool bufferBinResolution = false; | 1869 bool bufferIsBinResolution = false; |
2192 if (increment > zoomLevel) bufferBinResolution = true; | 1870 if (increment > zoomLevel) bufferIsBinResolution = true; |
2193 | 1871 |
2194 sv_frame_t leftBoundaryFrame = -1, leftCropFrame = -1; | 1872 sv_frame_t leftBoundaryFrame = -1, leftCropFrame = -1; |
2195 sv_frame_t rightBoundaryFrame = -1, rightCropFrame = -1; | 1873 sv_frame_t rightBoundaryFrame = -1, rightCropFrame = -1; |
2196 | 1874 |
2197 int bufwid; | 1875 int bufwid; |
2198 | 1876 |
2199 if (bufferBinResolution) { | 1877 if (bufferIsBinResolution) { |
2200 | 1878 |
2201 for (int x = x0; ; --x) { | 1879 for (int x = x0; ; --x) { |
2202 sv_frame_t f = v->getFrameForX(x); | 1880 sv_frame_t f = v->getFrameForX(x); |
2203 if ((f / increment) * increment == f) { | 1881 if ((f / increment) * increment == f) { |
2204 if (leftCropFrame == -1) leftCropFrame = f; | 1882 if (leftCropFrame == -1) leftCropFrame = f; |
2205 else if (x < x0 - 2) { leftBoundaryFrame = f; break; } | 1883 else if (x < x0 - 2) { |
1884 leftBoundaryFrame = f; | |
1885 break; | |
1886 } | |
2206 } | 1887 } |
2207 } | 1888 } |
2208 for (int x = x0 + w; ; ++x) { | 1889 for (int x = x0 + repaintWidth; ; ++x) { |
2209 sv_frame_t f = v->getFrameForX(x); | 1890 sv_frame_t f = v->getFrameForX(x); |
2210 if ((f / increment) * increment == f) { | 1891 if ((f / increment) * increment == f) { |
2211 if (rightCropFrame == -1) rightCropFrame = f; | 1892 if (rightCropFrame == -1) rightCropFrame = f; |
2212 else if (x > x0 + w + 2) { rightBoundaryFrame = f; break; } | 1893 else if (x > x0 + repaintWidth + 2) { |
1894 rightBoundaryFrame = f; | |
1895 break; | |
1896 } | |
2213 } | 1897 } |
2214 } | 1898 } |
2215 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1899 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2216 cerr << "Left: crop: " << leftCropFrame << " (bin " << leftCropFrame/increment << "); boundary: " << leftBoundaryFrame << " (bin " << leftBoundaryFrame/increment << ")" << endl; | 1900 cerr << "Left: crop: " << leftCropFrame << " (bin " << leftCropFrame/increment << "); boundary: " << leftBoundaryFrame << " (bin " << leftBoundaryFrame/increment << ")" << endl; |
2217 cerr << "Right: crop: " << rightCropFrame << " (bin " << rightCropFrame/increment << "); boundary: " << rightBoundaryFrame << " (bin " << rightBoundaryFrame/increment << ")" << endl; | 1901 cerr << "Right: crop: " << rightCropFrame << " (bin " << rightCropFrame/increment << "); boundary: " << rightBoundaryFrame << " (bin " << rightBoundaryFrame/increment << ")" << endl; |
2219 | 1903 |
2220 bufwid = int((rightBoundaryFrame - leftBoundaryFrame) / increment); | 1904 bufwid = int((rightBoundaryFrame - leftBoundaryFrame) / increment); |
2221 | 1905 |
2222 } else { | 1906 } else { |
2223 | 1907 |
2224 bufwid = w; | 1908 bufwid = repaintWidth; |
2225 } | 1909 } |
2226 | 1910 |
2227 vector<int> binforx(bufwid); | 1911 vector<int> binforx(bufwid); |
2228 vector<double> binfory(h); | 1912 vector<double> binfory(h); |
2229 | 1913 |
2230 bool usePeaksCache = false; | 1914 bool usePeaksCache = false; |
2231 | 1915 |
2232 if (bufferBinResolution) { | 1916 if (bufferIsBinResolution) { |
2233 for (int x = 0; x < bufwid; ++x) { | 1917 for (int x = 0; x < bufwid; ++x) { |
2234 binforx[x] = int(leftBoundaryFrame / increment) + x; | 1918 binforx[x] = int(leftBoundaryFrame / increment) + x; |
2235 // cerr << "binforx[" << x << "] = " << binforx[x] << endl; | |
2236 } | 1919 } |
2237 m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); | 1920 m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); |
2238 } else { | 1921 } else { |
2239 for (int x = 0; x < bufwid; ++x) { | 1922 for (int x = 0; x < bufwid; ++x) { |
2240 double s0 = 0, s1 = 0; | 1923 double s0 = 0, s1 = 0; |
2242 binforx[x] = int(s0 + 0.0001); | 1925 binforx[x] = int(s0 + 0.0001); |
2243 } else { | 1926 } else { |
2244 binforx[x] = -1; //??? | 1927 binforx[x] = -1; //??? |
2245 } | 1928 } |
2246 } | 1929 } |
2247 if (m_drawBuffer.width() < bufwid || m_drawBuffer.height() < h) { | 1930 if (m_drawBuffer.width() < bufwid || m_drawBuffer.height() != h) { |
2248 m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); | 1931 m_drawBuffer = QImage(bufwid, h, QImage::Format_Indexed8); |
2249 } | 1932 } |
2250 usePeaksCache = (increment * 8) < zoomLevel; | 1933 usePeaksCache = (increment * 8) < zoomLevel; |
2251 if (m_colourScale == PhaseColourScale) usePeaksCache = false; | 1934 if (m_colourScale == PhaseColourScale) usePeaksCache = false; |
2252 } | 1935 } |
2253 | 1936 |
2254 // No longer exists in Qt5: m_drawBuffer.setNumColors(256); | |
2255 for (int pixel = 0; pixel < 256; ++pixel) { | 1937 for (int pixel = 0; pixel < 256; ++pixel) { |
2256 m_drawBuffer.setColor((unsigned char)pixel, | 1938 m_drawBuffer.setColor((unsigned char)pixel, |
2257 m_palette.getColour((unsigned char)pixel).rgb()); | 1939 m_palette.getColour((unsigned char)pixel).rgb()); |
2258 } | 1940 } |
2259 | 1941 |
2260 m_drawBuffer.fill(0); | 1942 m_drawBuffer.fill(0); |
2261 | 1943 int attainedBufwid = bufwid; |
1944 | |
1945 double softTimeLimit; | |
1946 | |
1947 if (m_synchronous) { | |
1948 | |
1949 // must paint the whole thing for synchronous mode, so give | |
1950 // "no timeout" | |
1951 softTimeLimit = 0.0; | |
1952 | |
1953 } else if (bufferIsBinResolution) { | |
1954 | |
1955 // calculating boundaries later will be too fiddly for partial | |
1956 // paints, and painting should be fast anyway when this is the | |
1957 // case because it means we're well zoomed in | |
1958 softTimeLimit = 0.0; | |
1959 | |
1960 } else { | |
1961 | |
1962 // neither limitation applies, so use a short soft limit | |
1963 | |
1964 if (m_binDisplay == PeakFrequencies) { | |
1965 softTimeLimit = 0.15; | |
1966 } else { | |
1967 softTimeLimit = 0.1; | |
1968 } | |
1969 } | |
1970 | |
2262 if (m_binDisplay != PeakFrequencies) { | 1971 if (m_binDisplay != PeakFrequencies) { |
2263 | 1972 |
2264 for (int y = 0; y < h; ++y) { | 1973 for (int y = 0; y < h; ++y) { |
2265 double q0 = 0, q1 = 0; | 1974 double q0 = 0, q1 = 0; |
2266 if (!getSmoothedYBinRange(v, h-y-1, q0, q1)) { | 1975 if (!getSmoothedYBinRange(v, h-y-1, q0, q1)) { |
2267 binfory[y] = -1; | 1976 binfory[y] = -1; |
2268 } else { | 1977 } else { |
2269 binfory[y] = q0; | 1978 binfory[y] = q0; |
2270 // cerr << "binfory[" << y << "] = " << binfory[y] << endl; | |
2271 } | 1979 } |
2272 } | 1980 } |
2273 | 1981 |
2274 paintDrawBuffer(v, bufwid, h, binforx, binfory, usePeaksCache, | 1982 attainedBufwid = |
2275 overallMag, overallMagChanged); | 1983 paintDrawBuffer(v, bufwid, h, binforx, binfory, |
1984 usePeaksCache, | |
1985 overallMag, overallMagChanged, | |
1986 rightToLeft, | |
1987 softTimeLimit); | |
2276 | 1988 |
2277 } else { | 1989 } else { |
2278 | 1990 |
2279 paintDrawBufferPeakFrequencies(v, bufwid, h, binforx, | 1991 attainedBufwid = |
2280 minbin, maxbin, | 1992 paintDrawBufferPeakFrequencies(v, bufwid, h, binforx, |
2281 displayMinFreq, displayMaxFreq, | 1993 minbin, maxbin, |
2282 logarithmic, | 1994 displayMinFreq, displayMaxFreq, |
2283 overallMag, overallMagChanged); | 1995 logarithmic, |
2284 } | 1996 overallMag, overallMagChanged, |
2285 | 1997 rightToLeft, |
2286 /* | 1998 softTimeLimit); |
2287 for (int x = 0; x < w / xPixelRatio; ++x) { | 1999 } |
2288 | 2000 |
2289 Profiler innerprof("SpectrogramLayer::paint: 1 pixel column"); | 2001 int failedToRepaint = bufwid - attainedBufwid; |
2290 | 2002 |
2291 runOutOfData = !paintColumnValues(v, fft, x0, x, | 2003 int paintedLeft = x0; |
2292 minbin, maxbin, | 2004 int paintedWidth = x1 - x0; |
2293 displayMinFreq, displayMaxFreq, | 2005 |
2294 xPixelRatio, | 2006 if (failedToRepaint > 0) { |
2295 h, yforbin); | 2007 |
2296 | 2008 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2297 if (runOutOfData) { | 2009 cerr << "SpectrogramLayer::paint(): Failed to repaint " << failedToRepaint << " of " << bufwid |
2298 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2010 << " columns in time (so managed to repaint " << bufwid - failedToRepaint << ")" << endl; |
2299 cerr << "Run out of data -- dropping out of loop" << endl; | 2011 #endif |
2300 #endif | 2012 |
2301 break; | 2013 if (rightToLeft) { |
2302 } | 2014 paintedLeft += failedToRepaint; |
2303 } | 2015 } |
2304 */ | 2016 |
2305 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2017 paintedWidth -= failedToRepaint; |
2306 // cerr << pixels << " pixels drawn" << endl; | 2018 |
2307 #endif | 2019 if (paintedWidth < 0) { |
2020 paintedWidth = 0; | |
2021 } | |
2022 | |
2023 } else if (failedToRepaint < 0) { | |
2024 cerr << "WARNING: failedToRepaint < 0 (= " << failedToRepaint << ")" | |
2025 << endl; | |
2026 failedToRepaint = 0; | |
2027 } | |
2308 | 2028 |
2309 if (overallMagChanged) { | 2029 if (overallMagChanged) { |
2310 m_viewMags[v] = overallMag; | 2030 m_viewMags[v->getId()] = overallMag; |
2311 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2031 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2312 cerr << "Overall mag is now [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "] - will be updating" << endl; | 2032 cerr << "SpectrogramLayer: Overall mag is now [" << m_viewMags[v->getId()].getMin() << "->" << m_viewMags[v->getId()].getMax() << "] - will be updating" << endl; |
2313 #endif | |
2314 } else { | |
2315 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2316 cerr << "Overall mag unchanged at [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << endl; | |
2317 #endif | 2033 #endif |
2318 } | 2034 } |
2319 | 2035 |
2320 outerprof.end(); | 2036 outerprof.end(); |
2321 | 2037 |
2322 Profiler profiler2("SpectrogramLayer::paint: draw image"); | 2038 Profiler profiler2("SpectrogramLayer::paint: draw image"); |
2323 | 2039 |
2324 if (recreateWholeImageCache) { | 2040 if (paintedWidth > 0) { |
2325 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2041 |
2326 SVDEBUG << "Recreating image cache: width = " << v->width() | 2042 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2327 << ", height = " << h << endl; | 2043 cerr << "SpectrogramLayer: Copying " << paintedWidth << "x" << h |
2328 #endif | 2044 << " from draw buffer at " << paintedLeft - x0 << "," << 0 |
2329 cache.image = QImage(v->width(), h, QImage::Format_ARGB32_Premultiplied); | 2045 << " to " << paintedWidth << "x" << h << " on cache at " |
2330 } | |
2331 | |
2332 if (w > 0) { | |
2333 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2334 SVDEBUG << "Painting " << w << "x" << h | |
2335 << " from draw buffer at " << 0 << "," << 0 | |
2336 << " to " << w << "x" << h << " on cache at " | |
2337 << x0 << "," << 0 << endl; | 2046 << x0 << "," << 0 << endl; |
2338 #endif | 2047 #endif |
2339 | 2048 |
2340 QPainter cachePainter(&cache.image); | 2049 if (bufferIsBinResolution) { |
2341 | 2050 |
2342 if (bufferBinResolution) { | |
2343 int scaledLeft = v->getXForFrame(leftBoundaryFrame); | 2051 int scaledLeft = v->getXForFrame(leftBoundaryFrame); |
2344 int scaledRight = v->getXForFrame(rightBoundaryFrame); | 2052 int scaledRight = v->getXForFrame(rightBoundaryFrame); |
2345 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2053 |
2346 SVDEBUG << "Rescaling image from " << bufwid | 2054 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2055 cerr << "SpectrogramLayer: Rescaling image from " << bufwid | |
2347 << "x" << h << " to " | 2056 << "x" << h << " to " |
2348 << scaledRight-scaledLeft << "x" << h << endl; | 2057 << scaledRight-scaledLeft << "x" << h << endl; |
2349 #endif | 2058 #endif |
2059 | |
2350 Preferences::SpectrogramXSmoothing xsmoothing = | 2060 Preferences::SpectrogramXSmoothing xsmoothing = |
2351 Preferences::getInstance()->getSpectrogramXSmoothing(); | 2061 Preferences::getInstance()->getSpectrogramXSmoothing(); |
2352 // SVDEBUG << "xsmoothing == " << xsmoothing << endl; | 2062 |
2353 QImage scaled = m_drawBuffer.scaled | 2063 QImage scaled = m_drawBuffer.scaled |
2354 (scaledRight - scaledLeft, h, | 2064 (scaledRight - scaledLeft, h, |
2355 Qt::IgnoreAspectRatio, | 2065 Qt::IgnoreAspectRatio, |
2356 ((xsmoothing == Preferences::SpectrogramXInterpolated) ? | 2066 ((xsmoothing == Preferences::SpectrogramXInterpolated) ? |
2357 Qt::SmoothTransformation : Qt::FastTransformation)); | 2067 Qt::SmoothTransformation : Qt::FastTransformation)); |
2068 | |
2358 int scaledLeftCrop = v->getXForFrame(leftCropFrame); | 2069 int scaledLeftCrop = v->getXForFrame(leftCropFrame); |
2359 int scaledRightCrop = v->getXForFrame(rightCropFrame); | 2070 int scaledRightCrop = v->getXForFrame(rightCropFrame); |
2360 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2071 |
2361 SVDEBUG << "Drawing image region of width " << scaledRightCrop - scaledLeftCrop << " to " | 2072 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2073 cerr << "SpectrogramLayer: Drawing image region of width " << scaledRightCrop - scaledLeftCrop << " to " | |
2362 << scaledLeftCrop << " from " << scaledLeftCrop - scaledLeft << endl; | 2074 << scaledLeftCrop << " from " << scaledLeftCrop - scaledLeft << endl; |
2363 #endif | 2075 #endif |
2364 cachePainter.drawImage | 2076 |
2365 (QRect(scaledLeftCrop, 0, | 2077 int targetLeft = scaledLeftCrop; |
2366 scaledRightCrop - scaledLeftCrop, h), | 2078 if (targetLeft < 0) { |
2367 scaled, | 2079 targetLeft = 0; |
2368 QRect(scaledLeftCrop - scaledLeft, 0, | 2080 } |
2369 scaledRightCrop - scaledLeftCrop, h)); | 2081 |
2082 int targetWidth = scaledRightCrop - targetLeft; | |
2083 if (targetLeft + targetWidth > cache.getSize().width()) { | |
2084 targetWidth = cache.getSize().width() - targetLeft; | |
2085 } | |
2086 | |
2087 int sourceLeft = targetLeft - scaledLeft; | |
2088 if (sourceLeft < 0) { | |
2089 sourceLeft = 0; | |
2090 } | |
2091 | |
2092 int sourceWidth = targetWidth; | |
2093 | |
2094 if (targetWidth > 0) { | |
2095 cache.drawImage | |
2096 (targetLeft, | |
2097 targetWidth, | |
2098 scaled, | |
2099 sourceLeft, | |
2100 sourceWidth); | |
2101 } | |
2102 | |
2370 } else { | 2103 } else { |
2371 cachePainter.drawImage(QRect(x0, 0, w, h), | 2104 |
2372 m_drawBuffer, | 2105 cache.drawImage(paintedLeft, paintedWidth, |
2373 QRect(0, 0, w, h)); | 2106 m_drawBuffer, |
2374 } | 2107 paintedLeft - x0, paintedWidth); |
2375 | 2108 } |
2376 cachePainter.end(); | 2109 } |
2377 } | 2110 |
2378 | 2111 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2379 QRect pr = rect & cache.validArea; | 2112 cerr << "SpectrogramLayer: Cache valid area now from " << cache.getValidLeft() |
2380 | 2113 << " width " << cache.getValidWidth() << ", height " |
2381 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2114 << cache.getSize().height() << endl; |
2382 SVDEBUG << "Painting " << pr.width() << "x" << pr.height() | 2115 #endif |
2116 | |
2117 QRect pr = rect & cache.getValidArea(); | |
2118 | |
2119 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2120 cerr << "SpectrogramLayer: Copying " << pr.width() << "x" << pr.height() | |
2383 << " from cache at " << pr.x() << "," << pr.y() | 2121 << " from cache at " << pr.x() << "," << pr.y() |
2384 << " to window" << endl; | 2122 << " to window" << endl; |
2385 #endif | 2123 #endif |
2386 | 2124 |
2387 paint.drawImage(pr.x(), pr.y(), cache.image, | 2125 paint.drawImage(pr.x(), pr.y(), cache.getImage(), |
2388 pr.x(), pr.y(), pr.width(), pr.height()); | 2126 pr.x(), pr.y(), pr.width(), pr.height()); |
2389 //!!! | |
2390 // paint.drawImage(v->rect(), cache.image, | |
2391 // QRect(QPoint(0, 0), cache.image.size())); | |
2392 | |
2393 cache.startFrame = startFrame; | |
2394 cache.zoomLevel = zoomLevel; | |
2395 | 2127 |
2396 if (!m_synchronous) { | 2128 if (!m_synchronous) { |
2397 | 2129 |
2398 if (!m_normalizeVisibleArea || !overallMagChanged) { | 2130 if ((m_normalization != NormalizeVisibleArea) || !overallMagChanged) { |
2399 | 2131 |
2400 if (cache.validArea.x() > 0) { | 2132 QRect areaLeft(0, 0, cache.getValidLeft(), h); |
2401 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2133 QRect areaRight(cache.getValidRight(), 0, |
2402 SVDEBUG << "SpectrogramLayer::paint() updating left (0, " | 2134 cache.getSize().width() - cache.getValidRight(), h); |
2403 << cache.validArea.x() << ")" << endl; | 2135 |
2404 #endif | 2136 bool haveSpaceLeft = (areaLeft.width() > 0); |
2405 v->update(0, 0, cache.validArea.x(), h); | 2137 bool haveSpaceRight = (areaRight.width() > 0); |
2138 | |
2139 bool updateLeft = haveSpaceLeft; | |
2140 bool updateRight = haveSpaceRight; | |
2141 | |
2142 if (updateLeft && updateRight) { | |
2143 if (rightToLeft) { | |
2144 // we just did something adjoining the cache on | |
2145 // its left side, so now do something on its right | |
2146 updateLeft = false; | |
2147 } else { | |
2148 updateRight = false; | |
2149 } | |
2406 } | 2150 } |
2407 | 2151 |
2408 if (cache.validArea.x() + cache.validArea.width() < | 2152 if (updateLeft) { |
2409 cache.image.width()) { | 2153 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2410 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2154 cerr << "SpectrogramLayer::paint() updating left (" |
2411 SVDEBUG << "SpectrogramLayer::paint() updating right (" | 2155 << areaLeft.x() << ", " |
2412 << cache.validArea.x() + cache.validArea.width() | 2156 << areaLeft.width() << ")" << endl; |
2413 << ", " | 2157 #endif |
2414 << cache.image.width() - (cache.validArea.x() + | 2158 v->updatePaintRect(areaLeft); |
2415 cache.validArea.width()) | |
2416 << ")" << endl; | |
2417 #endif | |
2418 v->update(cache.validArea.x() + cache.validArea.width(), | |
2419 0, | |
2420 cache.image.width() - (cache.validArea.x() + | |
2421 cache.validArea.width()), | |
2422 h); | |
2423 } | 2159 } |
2160 | |
2161 if (updateRight) { | |
2162 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2163 cerr << "SpectrogramLayer::paint() updating right (" | |
2164 << areaRight.x() << ", " | |
2165 << areaRight.width() << ")" << endl; | |
2166 #endif | |
2167 v->updatePaintRect(areaRight); | |
2168 } | |
2169 | |
2424 } else { | 2170 } else { |
2425 // overallMagChanged | 2171 // overallMagChanged |
2426 cerr << "\noverallMagChanged - updating all\n" << endl; | 2172 cerr << "\noverallMagChanged - updating all\n" << endl; |
2427 cache.validArea = QRect(); | 2173 cache.invalidate(); |
2428 v->update(); | 2174 v->updatePaintRect(v->getPaintRect()); |
2429 } | 2175 } |
2430 } | 2176 } |
2431 | 2177 |
2432 illuminateLocalFeatures(v, paint); | 2178 illuminateLocalFeatures(v, paint); |
2433 | 2179 |
2434 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2180 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2435 SVDEBUG << "SpectrogramLayer::paint() returning" << endl; | 2181 cerr << "SpectrogramLayer::paint() returning" << endl; |
2436 #endif | 2182 #endif |
2437 | 2183 } |
2438 if (!m_synchronous) { | 2184 |
2439 m_lastPaintBlockWidth = paintBlockWidth; | 2185 int |
2440 (void)gettimeofday(&tv, 0); | 2186 SpectrogramLayer::paintDrawBufferPeakFrequencies(LayerGeometryProvider *v, |
2441 m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart; | |
2442 } | |
2443 } | |
2444 | |
2445 bool | |
2446 SpectrogramLayer::paintDrawBufferPeakFrequencies(View *v, | |
2447 int w, | 2187 int w, |
2448 int h, | 2188 int h, |
2449 const vector<int> &binforx, | 2189 const vector<int> &binforx, |
2450 int minbin, | 2190 int minbin, |
2451 int maxbin, | 2191 int maxbin, |
2452 double displayMinFreq, | 2192 double displayMinFreq, |
2453 double displayMaxFreq, | 2193 double displayMaxFreq, |
2454 bool logarithmic, | 2194 bool logarithmic, |
2455 MagnitudeRange &overallMag, | 2195 MagnitudeRange &overallMag, |
2456 bool &overallMagChanged) const | 2196 bool &overallMagChanged, |
2197 bool rightToLeft, | |
2198 double softTimeLimit) const | |
2457 { | 2199 { |
2458 Profiler profiler("SpectrogramLayer::paintDrawBufferPeakFrequencies"); | 2200 Profiler profiler("SpectrogramLayer::paintDrawBufferPeakFrequencies"); |
2459 | 2201 |
2460 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2202 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2461 cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; | 2203 cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; |
2462 #endif | 2204 #endif |
2463 if (minbin < 0) minbin = 0; | 2205 if (minbin < 0) minbin = 0; |
2464 if (maxbin < 0) maxbin = minbin+1; | 2206 if (maxbin < 0) maxbin = minbin+1; |
2465 | 2207 |
2466 FFTModel *fft = getFFTModel(v); | 2208 FFTModel *fft = getFFTModel(v); |
2467 if (!fft) return false; | 2209 if (!fft) return 0; |
2468 | 2210 |
2469 FFTModel::PeakSet peakfreqs; | 2211 FFTModel::PeakSet peakfreqs; |
2470 | 2212 |
2471 int psx = -1; | 2213 int psx = -1; |
2472 | 2214 |
2474 float values[maxbin - minbin + 1]; | 2216 float values[maxbin - minbin + 1]; |
2475 #else | 2217 #else |
2476 float *values = (float *)alloca((maxbin - minbin + 1) * sizeof(float)); | 2218 float *values = (float *)alloca((maxbin - minbin + 1) * sizeof(float)); |
2477 #endif | 2219 #endif |
2478 | 2220 |
2479 for (int x = 0; x < w; ++x) { | 2221 int minColumns = 4; |
2222 bool haveTimeLimits = (softTimeLimit > 0.0); | |
2223 double hardTimeLimit = softTimeLimit * 2.0; | |
2224 bool overridingSoftLimit = false; | |
2225 auto startTime = chrono::steady_clock::now(); | |
2226 | |
2227 int start = 0; | |
2228 int finish = w; | |
2229 int step = 1; | |
2230 | |
2231 if (rightToLeft) { | |
2232 start = w-1; | |
2233 finish = -1; | |
2234 step = -1; | |
2235 } | |
2236 | |
2237 int columnCount = 0; | |
2238 | |
2239 for (int x = start; x != finish; x += step) { | |
2240 | |
2241 ++columnCount; | |
2480 | 2242 |
2481 if (binforx[x] < 0) continue; | 2243 if (binforx[x] < 0) continue; |
2482 | 2244 |
2483 int sx0 = binforx[x]; | 2245 int sx0 = binforx[x]; |
2484 int sx1 = sx0; | 2246 int sx1 = sx0; |
2489 | 2251 |
2490 for (int sx = sx0; sx < sx1; ++sx) { | 2252 for (int sx = sx0; sx < sx1; ++sx) { |
2491 | 2253 |
2492 if (sx < 0 || sx >= int(fft->getWidth())) continue; | 2254 if (sx < 0 || sx >= int(fft->getWidth())) continue; |
2493 | 2255 |
2494 if (!m_synchronous) { | |
2495 if (!fft->isColumnAvailable(sx)) { | |
2496 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2497 cerr << "Met unavailable column at col " << sx << endl; | |
2498 #endif | |
2499 return false; | |
2500 } | |
2501 } | |
2502 | |
2503 MagnitudeRange mag; | 2256 MagnitudeRange mag; |
2504 | 2257 |
2505 if (sx != psx) { | 2258 if (sx != psx) { |
2506 peakfreqs = fft->getPeakFrequencies(FFTModel::AllPeaks, sx, | 2259 peakfreqs = fft->getPeakFrequencies(FFTModel::AllPeaks, sx, |
2507 minbin, maxbin - 1); | 2260 minbin, maxbin - 1); |
2508 if (m_colourScale == PhaseColourScale) { | 2261 if (m_colourScale == PhaseColourScale) { |
2509 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); | 2262 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); |
2510 } else if (m_normalizeColumns) { | 2263 } else if (m_normalization == NormalizeColumns) { |
2511 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2264 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2512 } else if (m_normalizeHybrid) { | 2265 } else if (m_normalization == NormalizeHybrid) { |
2513 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2266 float max = fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2514 double max = fft->getMaximumMagnitudeAt(sx); | |
2515 if (max > 0.f) { | 2267 if (max > 0.f) { |
2516 for (int i = minbin; i <= maxbin; ++i) { | 2268 for (int i = minbin; i <= maxbin; ++i) { |
2517 values[i - minbin] = float(values[i - minbin] * log10(max)); | 2269 values[i - minbin] = float(values[i - minbin] * |
2270 log10f(max)); | |
2518 } | 2271 } |
2519 } | 2272 } |
2520 } else { | 2273 } else { |
2521 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2274 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2522 } | 2275 } |
2533 if (bin > maxbin) break; | 2286 if (bin > maxbin) break; |
2534 | 2287 |
2535 double value = values[bin - minbin]; | 2288 double value = values[bin - minbin]; |
2536 | 2289 |
2537 if (m_colourScale != PhaseColourScale) { | 2290 if (m_colourScale != PhaseColourScale) { |
2538 if (!m_normalizeColumns && !m_normalizeHybrid) { | 2291 if (m_normalization != NormalizeColumns) { |
2539 value /= (m_fftSize/2.0); | 2292 value /= (m_fftSize/2.0); |
2540 } | 2293 } |
2541 mag.sample(float(value)); | 2294 mag.sample(float(value)); |
2542 value *= m_gain; | 2295 value *= m_gain; |
2543 } | 2296 } |
2563 m_columnMags[sx].sample(mag); | 2316 m_columnMags[sx].sample(mag); |
2564 if (overallMag.sample(mag)) overallMagChanged = true; | 2317 if (overallMag.sample(mag)) overallMagChanged = true; |
2565 } | 2318 } |
2566 } | 2319 } |
2567 } | 2320 } |
2568 } | 2321 |
2569 | 2322 if (haveTimeLimits) { |
2570 return true; | 2323 if (columnCount >= minColumns) { |
2571 } | 2324 auto t = chrono::steady_clock::now(); |
2572 | 2325 double diff = chrono::duration<double>(t - startTime).count(); |
2573 bool | 2326 if (diff > hardTimeLimit) { |
2574 SpectrogramLayer::paintDrawBuffer(View *v, | 2327 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2328 cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: hard limit " << hardTimeLimit << " sec exceeded after " | |
2329 << columnCount << " columns with time " << diff << endl; | |
2330 #endif | |
2331 return columnCount; | |
2332 } else if (diff > softTimeLimit && !overridingSoftLimit) { | |
2333 // If we're more than half way through by the time | |
2334 // we reach the soft limit, ignore it (though | |
2335 // still respect the hard limit, above). Otherwise | |
2336 // respect the soft limit and return now. | |
2337 if (columnCount > w/2) { | |
2338 overridingSoftLimit = true; | |
2339 } else { | |
2340 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2341 cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: soft limit " << softTimeLimit << " sec exceeded after " | |
2342 << columnCount << " columns with time " << diff << endl; | |
2343 #endif | |
2344 return columnCount; | |
2345 } | |
2346 } | |
2347 } | |
2348 } | |
2349 } | |
2350 | |
2351 return columnCount; | |
2352 } | |
2353 | |
2354 int | |
2355 SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v, | |
2575 int w, | 2356 int w, |
2576 int h, | 2357 int h, |
2577 const vector<int> &binforx, | 2358 const vector<int> &binforx, |
2578 const vector<double> &binfory, | 2359 const vector<double> &binfory, |
2579 bool usePeaksCache, | 2360 bool usePeaksCache, |
2580 MagnitudeRange &overallMag, | 2361 MagnitudeRange &overallMag, |
2581 bool &overallMagChanged) const | 2362 bool &overallMagChanged, |
2363 bool rightToLeft, | |
2364 double softTimeLimit) const | |
2582 { | 2365 { |
2583 Profiler profiler("SpectrogramLayer::paintDrawBuffer"); | 2366 Profiler profiler("SpectrogramLayer::paintDrawBuffer"); |
2584 | 2367 |
2585 int minbin = int(binfory[0] + 0.0001); | 2368 int minbin = int(binfory[0] + 0.0001); |
2586 int maxbin = int(binfory[h-1]); | 2369 int maxbin = int(binfory[h-1]); |
2587 | 2370 |
2588 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2371 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2589 cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; | 2372 cerr << "SpectrogramLayer::paintDrawBuffer: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; |
2590 #endif | 2373 #endif |
2591 if (minbin < 0) minbin = 0; | 2374 if (minbin < 0) minbin = 0; |
2592 if (maxbin < 0) maxbin = minbin+1; | 2375 if (maxbin < 0) maxbin = minbin+1; |
2593 | 2376 |
2594 DenseThreeDimensionalModel *sourceModel = 0; | 2377 DenseThreeDimensionalModel *sourceModel = 0; |
2595 FFTModel *fft = 0; | 2378 FFTModel *fft = 0; |
2596 int divisor = 1; | 2379 int divisor = 1; |
2597 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2380 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2598 cerr << "Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; | 2381 cerr << "SpectrogramLayer::paintDrawBuffer: Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; |
2599 #endif | 2382 #endif |
2600 if (usePeaksCache) { //!!! | 2383 if (usePeaksCache) { //!!! |
2601 sourceModel = getPeakCache(v); | 2384 sourceModel = getPeakCache(v); |
2602 divisor = 8;//!!! | 2385 divisor = 8;//!!! |
2603 minbin = 0; | 2386 minbin = 0; |
2604 maxbin = sourceModel->getHeight(); | 2387 maxbin = sourceModel->getHeight(); |
2605 } else { | 2388 } else { |
2606 sourceModel = fft = getFFTModel(v); | 2389 sourceModel = fft = getFFTModel(v); |
2607 } | 2390 } |
2608 | 2391 |
2609 if (!sourceModel) return false; | 2392 if (!sourceModel) return 0; |
2610 | 2393 |
2611 bool interpolate = false; | 2394 bool interpolate = false; |
2612 Preferences::SpectrogramSmoothing smoothing = | 2395 Preferences::SpectrogramSmoothing smoothing = |
2613 Preferences::getInstance()->getSpectrogramSmoothing(); | 2396 Preferences::getInstance()->getSpectrogramSmoothing(); |
2614 if (smoothing == Preferences::SpectrogramInterpolated || | 2397 if (smoothing == Preferences::SpectrogramInterpolated || |
2630 #endif | 2413 #endif |
2631 | 2414 |
2632 const float *values = autoarray; | 2415 const float *values = autoarray; |
2633 DenseThreeDimensionalModel::Column c; | 2416 DenseThreeDimensionalModel::Column c; |
2634 | 2417 |
2635 for (int x = 0; x < w; ++x) { | 2418 int minColumns = 4; |
2419 bool haveTimeLimits = (softTimeLimit > 0.0); | |
2420 double hardTimeLimit = softTimeLimit * 2.0; | |
2421 bool overridingSoftLimit = false; | |
2422 auto startTime = chrono::steady_clock::now(); | |
2423 | |
2424 int start = 0; | |
2425 int finish = w; | |
2426 int step = 1; | |
2427 | |
2428 if (rightToLeft) { | |
2429 start = w-1; | |
2430 finish = -1; | |
2431 step = -1; | |
2432 } | |
2433 | |
2434 int columnCount = 0; | |
2435 | |
2436 for (int x = start; x != finish; x += step) { | |
2437 | |
2438 ++columnCount; | |
2636 | 2439 |
2637 if (binforx[x] < 0) continue; | 2440 if (binforx[x] < 0) continue; |
2638 | 2441 |
2639 // float columnGain = m_gain; | 2442 // float columnGain = m_gain; |
2640 float columnMax = 0.f; | 2443 float columnMax = 0.f; |
2654 // cerr << "sx = " << sx << endl; | 2457 // cerr << "sx = " << sx << endl; |
2655 #endif | 2458 #endif |
2656 | 2459 |
2657 if (sx < 0 || sx >= int(sourceModel->getWidth())) continue; | 2460 if (sx < 0 || sx >= int(sourceModel->getWidth())) continue; |
2658 | 2461 |
2659 if (!m_synchronous) { | |
2660 if (!sourceModel->isColumnAvailable(sx)) { | |
2661 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2662 cerr << "Met unavailable column at col " << sx << endl; | |
2663 #endif | |
2664 return false; | |
2665 } | |
2666 } | |
2667 | |
2668 MagnitudeRange mag; | 2462 MagnitudeRange mag; |
2669 | 2463 |
2670 if (sx != psx) { | 2464 if (sx != psx) { |
2671 if (fft) { | 2465 if (fft) { |
2672 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2466 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2673 SVDEBUG << "Retrieving column " << sx << " from fft directly" << endl; | 2467 // cerr << "Retrieving column " << sx << " from fft directly" << endl; |
2674 #endif | 2468 #endif |
2675 if (m_colourScale == PhaseColourScale) { | 2469 if (m_colourScale == PhaseColourScale) { |
2676 fft->getPhasesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2470 fft->getPhasesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2677 } else if (m_normalizeColumns) { | 2471 } else if (m_normalization == NormalizeColumns) { |
2678 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2472 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2679 } else if (m_normalizeHybrid) { | 2473 } else if (m_normalization == NormalizeHybrid) { |
2680 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2474 float max = fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2681 double max = fft->getMaximumMagnitudeAt(sx); | 2475 float scale = log10f(max + 1.f); |
2476 // cout << "sx = " << sx << ", max = " << max << ", log10(max) = " << log10(max) << ", scale = " << scale << endl; | |
2682 for (int i = minbin; i <= maxbin; ++i) { | 2477 for (int i = minbin; i <= maxbin; ++i) { |
2683 if (max > 0.0) { | 2478 autoarray[i - minbin] *= scale; |
2684 autoarray[i - minbin] = float(autoarray[i - minbin] * log10(max)); | |
2685 } | |
2686 } | 2479 } |
2687 } else { | 2480 } else { |
2688 fft->getMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2481 fft->getMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); |
2689 } | 2482 } |
2690 } else { | 2483 } else { |
2691 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2484 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2692 SVDEBUG << "Retrieving column " << sx << " from peaks cache" << endl; | 2485 // cerr << "Retrieving column " << sx << " from peaks cache" << endl; |
2693 #endif | 2486 #endif |
2694 c = sourceModel->getColumn(sx); | 2487 c = sourceModel->getColumn(sx); |
2695 if (m_normalizeColumns || m_normalizeHybrid) { | 2488 if (m_normalization == NormalizeColumns || |
2489 m_normalization == NormalizeHybrid) { | |
2696 for (int y = 0; y < h; ++y) { | 2490 for (int y = 0; y < h; ++y) { |
2697 if (c[y] > columnMax) columnMax = c[y]; | 2491 if (c[y] > columnMax) columnMax = c[y]; |
2698 } | 2492 } |
2699 } | 2493 } |
2700 values = c.constData() + minbin; | 2494 values = c.data() + minbin; |
2701 } | 2495 } |
2702 psx = sx; | 2496 psx = sx; |
2703 } | 2497 } |
2704 | 2498 |
2705 for (int y = 0; y < h; ++y) { | 2499 for (int y = 0; y < h; ++y) { |
2733 } | 2527 } |
2734 if (v0 == 0.0 && v1 == 0.0) continue; | 2528 if (v0 == 0.0 && v1 == 0.0) continue; |
2735 value = prop * v0 + (1.0 - prop) * v1; | 2529 value = prop * v0 + (1.0 - prop) * v1; |
2736 | 2530 |
2737 if (m_colourScale != PhaseColourScale) { | 2531 if (m_colourScale != PhaseColourScale) { |
2738 if (!m_normalizeColumns) { | 2532 if (m_normalization != NormalizeColumns && |
2533 m_normalization != NormalizeHybrid) { | |
2739 value /= (m_fftSize/2.0); | 2534 value /= (m_fftSize/2.0); |
2740 } | 2535 } |
2741 mag.sample(float(value)); | 2536 mag.sample(float(value)); |
2742 value *= m_gain; | 2537 value *= m_gain; |
2743 } | 2538 } |
2758 value < values[bin-minbin-1] || | 2553 value < values[bin-minbin-1] || |
2759 value < values[bin-minbin+1]) continue; | 2554 value < values[bin-minbin+1]) continue; |
2760 } | 2555 } |
2761 | 2556 |
2762 if (m_colourScale != PhaseColourScale) { | 2557 if (m_colourScale != PhaseColourScale) { |
2763 if (!m_normalizeColumns) { | 2558 if (m_normalization != NormalizeColumns && |
2559 m_normalization != NormalizeHybrid) { | |
2764 value /= (m_fftSize/2.0); | 2560 value /= (m_fftSize/2.0); |
2765 } | 2561 } |
2766 mag.sample(float(value)); | 2562 mag.sample(float(value)); |
2767 value *= m_gain; | 2563 value *= m_gain; |
2768 } | 2564 } |
2792 for (int y = 0; y < h; ++y) { | 2588 for (int y = 0; y < h; ++y) { |
2793 | 2589 |
2794 double peak = peaks[y]; | 2590 double peak = peaks[y]; |
2795 | 2591 |
2796 if (m_colourScale != PhaseColourScale && | 2592 if (m_colourScale != PhaseColourScale && |
2797 (m_normalizeColumns || m_normalizeHybrid) && | 2593 (m_normalization == NormalizeColumns || |
2594 m_normalization == NormalizeHybrid) && | |
2798 columnMax > 0.f) { | 2595 columnMax > 0.f) { |
2799 peak /= columnMax; | 2596 peak /= columnMax; |
2800 if (m_normalizeHybrid) { | 2597 if (m_normalization == NormalizeHybrid) { |
2801 peak *= log10(columnMax); | 2598 peak *= log10(columnMax + 1.f); |
2802 } | 2599 } |
2803 } | 2600 } |
2804 | 2601 |
2805 unsigned char peakpix = getDisplayValue(v, peak); | 2602 unsigned char peakpix = getDisplayValue(v, peak); |
2806 | 2603 |
2807 m_drawBuffer.setPixel(x, h-y-1, peakpix); | 2604 m_drawBuffer.setPixel(x, h-y-1, peakpix); |
2808 } | 2605 } |
2809 } | 2606 |
2810 | 2607 if (haveTimeLimits) { |
2811 return true; | 2608 if (columnCount >= minColumns) { |
2609 auto t = chrono::steady_clock::now(); | |
2610 double diff = chrono::duration<double>(t - startTime).count(); | |
2611 if (diff > hardTimeLimit) { | |
2612 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2613 cerr << "SpectrogramLayer::paintDrawBuffer: hard limit " << hardTimeLimit << " sec exceeded after " | |
2614 << columnCount << " columns with time " << diff << endl; | |
2615 #endif | |
2616 return columnCount; | |
2617 } else if (diff > softTimeLimit && !overridingSoftLimit) { | |
2618 // If we're more than half way through by the time | |
2619 // we reach the soft limit, ignore it (though | |
2620 // still respect the hard limit, above). Otherwise | |
2621 // respect the soft limit and return now. | |
2622 if (columnCount > w/2) { | |
2623 overridingSoftLimit = true; | |
2624 } else { | |
2625 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2626 cerr << "SpectrogramLayer::paintDrawBuffer: soft limit " << softTimeLimit << " sec exceeded after " | |
2627 << columnCount << " columns with time " << diff << endl; | |
2628 #endif | |
2629 return columnCount; | |
2630 } | |
2631 } | |
2632 } | |
2633 } | |
2634 } | |
2635 | |
2636 return columnCount; | |
2812 } | 2637 } |
2813 | 2638 |
2814 void | 2639 void |
2815 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const | 2640 SpectrogramLayer::illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &paint) const |
2816 { | 2641 { |
2817 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); | 2642 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); |
2818 | 2643 |
2819 QPoint localPos; | 2644 QPoint localPos; |
2820 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) { | 2645 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) { |
2849 paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1); | 2674 paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1); |
2850 } | 2675 } |
2851 } | 2676 } |
2852 | 2677 |
2853 double | 2678 double |
2854 SpectrogramLayer::getYForFrequency(const View *v, double frequency) const | 2679 SpectrogramLayer::getYForFrequency(const LayerGeometryProvider *v, double frequency) const |
2855 { | 2680 { |
2856 return v->getYForFrequency(frequency, | 2681 return v->getYForFrequency(frequency, |
2857 getEffectiveMinFrequency(), | 2682 getEffectiveMinFrequency(), |
2858 getEffectiveMaxFrequency(), | 2683 getEffectiveMaxFrequency(), |
2859 m_frequencyScale == LogFrequencyScale); | 2684 m_frequencyScale == LogFrequencyScale); |
2860 } | 2685 } |
2861 | 2686 |
2862 double | 2687 double |
2863 SpectrogramLayer::getFrequencyForY(const View *v, int y) const | 2688 SpectrogramLayer::getFrequencyForY(const LayerGeometryProvider *v, int y) const |
2864 { | 2689 { |
2865 return v->getFrequencyForY(y, | 2690 return v->getFrequencyForY(y, |
2866 getEffectiveMinFrequency(), | 2691 getEffectiveMinFrequency(), |
2867 getEffectiveMaxFrequency(), | 2692 getEffectiveMaxFrequency(), |
2868 m_frequencyScale == LogFrequencyScale); | 2693 m_frequencyScale == LogFrequencyScale); |
2869 } | 2694 } |
2870 | 2695 |
2871 int | 2696 int |
2872 SpectrogramLayer::getCompletion(View *v) const | 2697 SpectrogramLayer::getCompletion(LayerGeometryProvider *v) const |
2873 { | 2698 { |
2874 if (m_updateTimer == 0) return 100; | 2699 const View *view = v->getView(); |
2875 if (m_fftModels.find(v) == m_fftModels.end()) return 100; | 2700 |
2876 | 2701 if (m_fftModels.find(view->getId()) == m_fftModels.end()) return 100; |
2877 int completion = m_fftModels[v].first->getCompletion(); | 2702 |
2878 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2703 int completion = m_fftModels[view->getId()]->getCompletion(); |
2879 SVDEBUG << "SpectrogramLayer::getCompletion: completion = " << completion << endl; | 2704 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2705 cerr << "SpectrogramLayer::getCompletion: completion = " << completion << endl; | |
2880 #endif | 2706 #endif |
2881 return completion; | 2707 return completion; |
2882 } | 2708 } |
2883 | 2709 |
2884 QString | 2710 QString |
2885 SpectrogramLayer::getError(View *v) const | 2711 SpectrogramLayer::getError(LayerGeometryProvider *v) const |
2886 { | 2712 { |
2887 if (m_fftModels.find(v) == m_fftModels.end()) return ""; | 2713 const View *view = v->getView(); |
2888 return m_fftModels[v].first->getError(); | 2714 if (m_fftModels.find(view->getId()) == m_fftModels.end()) return ""; |
2715 return m_fftModels[view->getId()]->getError(); | |
2889 } | 2716 } |
2890 | 2717 |
2891 bool | 2718 bool |
2892 SpectrogramLayer::getValueExtents(double &min, double &max, | 2719 SpectrogramLayer::getValueExtents(double &min, double &max, |
2893 bool &logarithmic, QString &unit) const | 2720 bool &logarithmic, QString &unit) const |
2944 | 2771 |
2945 return true; | 2772 return true; |
2946 } | 2773 } |
2947 | 2774 |
2948 bool | 2775 bool |
2949 SpectrogramLayer::getYScaleValue(const View *v, int y, | 2776 SpectrogramLayer::getYScaleValue(const LayerGeometryProvider *v, int y, |
2950 double &value, QString &unit) const | 2777 double &value, QString &unit) const |
2951 { | 2778 { |
2952 value = getFrequencyForY(v, y); | 2779 value = getFrequencyForY(v, y); |
2953 unit = "Hz"; | 2780 unit = "Hz"; |
2954 return true; | 2781 return true; |
2955 } | 2782 } |
2956 | 2783 |
2957 bool | 2784 bool |
2958 SpectrogramLayer::snapToFeatureFrame(View *, | 2785 SpectrogramLayer::snapToFeatureFrame(LayerGeometryProvider *, |
2959 sv_frame_t &frame, | 2786 sv_frame_t &frame, |
2960 int &resolution, | 2787 int &resolution, |
2961 SnapType snap) const | 2788 SnapType snap) const |
2962 { | 2789 { |
2963 resolution = getWindowIncrement(); | 2790 resolution = getWindowIncrement(); |
2976 | 2803 |
2977 return true; | 2804 return true; |
2978 } | 2805 } |
2979 | 2806 |
2980 void | 2807 void |
2981 SpectrogramLayer::measureDoubleClick(View *v, QMouseEvent *e) | 2808 SpectrogramLayer::measureDoubleClick(LayerGeometryProvider *v, QMouseEvent *e) |
2982 { | 2809 { |
2983 ImageCache &cache = m_imageCaches[v]; | 2810 const View *view = v->getView(); |
2984 | 2811 ScrollableImageCache &cache = getImageCacheReference(view); |
2985 cerr << "cache width: " << cache.image.width() << ", height: " | 2812 |
2986 << cache.image.height() << endl; | 2813 cerr << "cache width: " << cache.getSize().width() << ", height: " |
2987 | 2814 << cache.getSize().height() << endl; |
2988 QImage image = cache.image; | 2815 |
2816 QImage image = cache.getImage(); | |
2989 | 2817 |
2990 ImageRegionFinder finder; | 2818 ImageRegionFinder finder; |
2991 QRect rect = finder.findRegionExtents(&image, e->pos()); | 2819 QRect rect = finder.findRegionExtents(&image, e->pos()); |
2992 if (rect.isValid()) { | 2820 if (rect.isValid()) { |
2993 MeasureRect mr; | 2821 MeasureRect mr; |
2996 (new AddMeasurementRectCommand(this, mr)); | 2824 (new AddMeasurementRectCommand(this, mr)); |
2997 } | 2825 } |
2998 } | 2826 } |
2999 | 2827 |
3000 bool | 2828 bool |
3001 SpectrogramLayer::getCrosshairExtents(View *v, QPainter &paint, | 2829 SpectrogramLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint, |
3002 QPoint cursorPos, | 2830 QPoint cursorPos, |
3003 std::vector<QRect> &extents) const | 2831 vector<QRect> &extents) const |
3004 { | 2832 { |
3005 QRect vertical(cursorPos.x() - 12, 0, 12, v->height()); | 2833 QRect vertical(cursorPos.x() - 12, 0, 12, v->getPaintHeight()); |
3006 extents.push_back(vertical); | 2834 extents.push_back(vertical); |
3007 | 2835 |
3008 QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1); | 2836 QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1); |
3009 extents.push_back(horizontal); | 2837 extents.push_back(horizontal); |
3010 | 2838 |
3019 paint.fontMetrics().width("C#10+50c") + 2, | 2847 paint.fontMetrics().width("C#10+50c") + 2, |
3020 paint.fontMetrics().height()); | 2848 paint.fontMetrics().height()); |
3021 extents.push_back(pitch); | 2849 extents.push_back(pitch); |
3022 | 2850 |
3023 QRect rt(cursorPos.x(), | 2851 QRect rt(cursorPos.x(), |
3024 v->height() - paint.fontMetrics().height() - 2, | 2852 v->getPaintHeight() - paint.fontMetrics().height() - 2, |
3025 paint.fontMetrics().width("1234.567 s"), | 2853 paint.fontMetrics().width("1234.567 s"), |
3026 paint.fontMetrics().height()); | 2854 paint.fontMetrics().height()); |
3027 extents.push_back(rt); | 2855 extents.push_back(rt); |
3028 | 2856 |
3029 int w(paint.fontMetrics().width("1234567890") + 2); | 2857 int w(paint.fontMetrics().width("1234567890") + 2); |
3030 QRect frame(cursorPos.x() - w - 2, | 2858 QRect frame(cursorPos.x() - w - 2, |
3031 v->height() - paint.fontMetrics().height() - 2, | 2859 v->getPaintHeight() - paint.fontMetrics().height() - 2, |
3032 w, | 2860 w, |
3033 paint.fontMetrics().height()); | 2861 paint.fontMetrics().height()); |
3034 extents.push_back(frame); | 2862 extents.push_back(frame); |
3035 | 2863 |
3036 return true; | 2864 return true; |
3037 } | 2865 } |
3038 | 2866 |
3039 void | 2867 void |
3040 SpectrogramLayer::paintCrosshairs(View *v, QPainter &paint, | 2868 SpectrogramLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint, |
3041 QPoint cursorPos) const | 2869 QPoint cursorPos) const |
3042 { | 2870 { |
3043 paint.save(); | 2871 paint.save(); |
3044 | 2872 |
3045 int sw = getVerticalScaleWidth(v, m_haveDetailedScale, paint); | 2873 int sw = getVerticalScaleWidth(v, m_haveDetailedScale, paint); |
3050 paint.setFont(fn); | 2878 paint.setFont(fn); |
3051 } | 2879 } |
3052 paint.setPen(m_crosshairColour); | 2880 paint.setPen(m_crosshairColour); |
3053 | 2881 |
3054 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); | 2882 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); |
3055 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->height()); | 2883 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->getPaintHeight()); |
3056 | 2884 |
3057 double fundamental = getFrequencyForY(v, cursorPos.y()); | 2885 double fundamental = getFrequencyForY(v, cursorPos.y()); |
3058 | 2886 |
3059 v->drawVisibleText(paint, | 2887 v->drawVisibleText(paint, |
3060 sw + 2, | 2888 sw + 2, |
3075 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate()); | 2903 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate()); |
3076 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); | 2904 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); |
3077 QString frameLabel = QString("%1").arg(frame); | 2905 QString frameLabel = QString("%1").arg(frame); |
3078 v->drawVisibleText(paint, | 2906 v->drawVisibleText(paint, |
3079 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, | 2907 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, |
3080 v->height() - 2, | 2908 v->getPaintHeight() - 2, |
3081 frameLabel, | 2909 frameLabel, |
3082 View::OutlinedText); | 2910 View::OutlinedText); |
3083 v->drawVisibleText(paint, | 2911 v->drawVisibleText(paint, |
3084 cursorPos.x() + 2, | 2912 cursorPos.x() + 2, |
3085 v->height() - 2, | 2913 v->getPaintHeight() - 2, |
3086 rtLabel, | 2914 rtLabel, |
3087 View::OutlinedText); | 2915 View::OutlinedText); |
3088 | 2916 |
3089 int harmonic = 2; | 2917 int harmonic = 2; |
3090 | 2918 |
3091 while (harmonic < 100) { | 2919 while (harmonic < 100) { |
3092 | 2920 |
3093 int hy = int(lrint(getYForFrequency(v, fundamental * harmonic))); | 2921 int hy = int(lrint(getYForFrequency(v, fundamental * harmonic))); |
3094 if (hy < 0 || hy > v->height()) break; | 2922 if (hy < 0 || hy > v->getPaintHeight()) break; |
3095 | 2923 |
3096 int len = 7; | 2924 int len = 7; |
3097 | 2925 |
3098 if (harmonic % 2 == 0) { | 2926 if (harmonic % 2 == 0) { |
3099 if (harmonic % 4 == 0) { | 2927 if (harmonic % 4 == 0) { |
3113 | 2941 |
3114 paint.restore(); | 2942 paint.restore(); |
3115 } | 2943 } |
3116 | 2944 |
3117 QString | 2945 QString |
3118 SpectrogramLayer::getFeatureDescription(View *v, QPoint &pos) const | 2946 SpectrogramLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const |
3119 { | 2947 { |
3120 int x = pos.x(); | 2948 int x = pos.x(); |
3121 int y = pos.y(); | 2949 int y = pos.y(); |
3122 | 2950 |
3123 if (!m_model || !m_model->isOK()) return ""; | 2951 if (!m_model || !m_model->isOK()) return ""; |
3235 | 3063 |
3236 return cw; | 3064 return cw; |
3237 } | 3065 } |
3238 | 3066 |
3239 int | 3067 int |
3240 SpectrogramLayer::getVerticalScaleWidth(View *, bool detailed, QPainter &paint) const | 3068 SpectrogramLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &paint) const |
3241 { | 3069 { |
3242 if (!m_model || !m_model->isOK()) return 0; | 3070 if (!m_model || !m_model->isOK()) return 0; |
3243 | 3071 |
3244 int cw = 0; | 3072 int cw = 0; |
3245 if (detailed) cw = getColourScaleWidth(paint); | 3073 if (detailed) cw = getColourScaleWidth(paint); |
3256 | 3084 |
3257 return cw + tickw + tw + 13; | 3085 return cw + tickw + tw + 13; |
3258 } | 3086 } |
3259 | 3087 |
3260 void | 3088 void |
3261 SpectrogramLayer::paintVerticalScale(View *v, bool detailed, QPainter &paint, QRect rect) const | 3089 SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const |
3262 { | 3090 { |
3263 if (!m_model || !m_model->isOK()) { | 3091 if (!m_model || !m_model->isOK()) { |
3264 return; | 3092 return; |
3265 } | 3093 } |
3266 | 3094 |
3298 int ch = h - textHeight * (topLines + 1) - 8; | 3126 int ch = h - textHeight * (topLines + 1) - 8; |
3299 // paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); | 3127 // paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); |
3300 paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1); | 3128 paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1); |
3301 | 3129 |
3302 QString top, bottom; | 3130 QString top, bottom; |
3303 double min = m_viewMags[v].getMin(); | 3131 double min = m_viewMags[v->getId()].getMin(); |
3304 double max = m_viewMags[v].getMax(); | 3132 double max = m_viewMags[v->getId()].getMax(); |
3305 | 3133 |
3306 double dBmin = AudioLevel::multiplier_to_dB(min); | 3134 double dBmin = AudioLevel::multiplier_to_dB(min); |
3307 double dBmax = AudioLevel::multiplier_to_dB(max); | 3135 double dBmax = AudioLevel::multiplier_to_dB(max); |
3308 | 3136 |
3137 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
3138 cerr << "paintVerticalScale: for view id " << v->getId() | |
3139 << ": min = " << min << ", max = " << max | |
3140 << ", dBmin = " << dBmin << ", dBmax = " << dBmax << endl; | |
3141 #endif | |
3142 | |
3309 if (dBmax < -60.f) dBmax = -60.f; | 3143 if (dBmax < -60.f) dBmax = -60.f; |
3310 else top = QString("%1").arg(lrint(dBmax)); | 3144 else top = QString("%1").arg(lrint(dBmax)); |
3311 | 3145 |
3312 if (dBmin < dBmax - 60.f) dBmin = dBmax - 60.f; | 3146 if (dBmin < dBmax - 60.f) dBmin = dBmax - 60.f; |
3313 bottom = QString("%1").arg(lrint(dBmin)); | 3147 bottom = QString("%1").arg(lrint(dBmin)); |
3370 | 3204 |
3371 paint.drawLine(cw + 7, 0, cw + 7, h); | 3205 paint.drawLine(cw + 7, 0, cw + 7, h); |
3372 | 3206 |
3373 int bin = -1; | 3207 int bin = -1; |
3374 | 3208 |
3375 for (int y = 0; y < v->height(); ++y) { | 3209 for (int y = 0; y < v->getPaintHeight(); ++y) { |
3376 | 3210 |
3377 double q0, q1; | 3211 double q0, q1; |
3378 if (!getYBinRange(v, v->height() - y, q0, q1)) continue; | 3212 if (!getYBinRange(v, v->getPaintHeight() - y, q0, q1)) continue; |
3379 | 3213 |
3380 int vy; | 3214 int vy; |
3381 | 3215 |
3382 if (int(q0) > bin) { | 3216 if (int(q0) > bin) { |
3383 vy = y; | 3217 vy = y; |
3398 QString text = QString("%1").arg(freq); | 3232 QString text = QString("%1").arg(freq); |
3399 if (bin == 1) text = tr("%1Hz").arg(freq); // bin 0 is DC | 3233 if (bin == 1) text = tr("%1Hz").arg(freq); // bin 0 is DC |
3400 paint.drawLine(cw + 7, h - vy, w - pkw - 1, h - vy); | 3234 paint.drawLine(cw + 7, h - vy, w - pkw - 1, h - vy); |
3401 | 3235 |
3402 if (h - vy - textHeight >= -2) { | 3236 if (h - vy - textHeight >= -2) { |
3403 int tx = w - 3 - paint.fontMetrics().width(text) - std::max(tickw, pkw); | 3237 int tx = w - 3 - paint.fontMetrics().width(text) - max(tickw, pkw); |
3404 paint.drawText(tx, h - vy + toff, text); | 3238 paint.drawText(tx, h - vy + toff, text); |
3405 } | 3239 } |
3406 | 3240 |
3407 py = vy; | 3241 py = vy; |
3408 } | 3242 } |
3587 if (!m_model) return 0; | 3421 if (!m_model) return 0; |
3588 return new SpectrogramRangeMapper(m_model->getSampleRate(), m_fftSize); | 3422 return new SpectrogramRangeMapper(m_model->getSampleRate(), m_fftSize); |
3589 } | 3423 } |
3590 | 3424 |
3591 void | 3425 void |
3592 SpectrogramLayer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const | 3426 SpectrogramLayer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const |
3593 { | 3427 { |
3594 int y0 = 0; | 3428 int y0 = 0; |
3595 if (r.startY > 0.0) y0 = int(getYForFrequency(v, r.startY)); | 3429 if (r.startY > 0.0) y0 = int(getYForFrequency(v, r.startY)); |
3596 | 3430 |
3597 int y1 = y0; | 3431 int y1 = y0; |
3601 | 3435 |
3602 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); | 3436 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); |
3603 } | 3437 } |
3604 | 3438 |
3605 void | 3439 void |
3606 SpectrogramLayer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const | 3440 SpectrogramLayer::setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const |
3607 { | 3441 { |
3608 if (start) { | 3442 if (start) { |
3609 r.startY = getFrequencyForY(v, y); | 3443 r.startY = getFrequencyForY(v, y); |
3610 r.endY = r.startY; | 3444 r.endY = r.startY; |
3611 } else { | 3445 } else { |
3645 .arg(m_colourMap) | 3479 .arg(m_colourMap) |
3646 .arg(m_colourRotation) | 3480 .arg(m_colourRotation) |
3647 .arg(m_frequencyScale) | 3481 .arg(m_frequencyScale) |
3648 .arg(m_binDisplay); | 3482 .arg(m_binDisplay); |
3649 | 3483 |
3650 s += QString("normalizeColumns=\"%1\" " | 3484 // New-style normalization attributes, allowing for more types of |
3651 "normalizeVisibleArea=\"%2\" " | 3485 // normalization in future: write out the column normalization |
3652 "normalizeHybrid=\"%3\" ") | 3486 // type separately, and then whether we are normalizing visible |
3653 .arg(m_normalizeColumns ? "true" : "false") | 3487 // area as well afterwards |
3654 .arg(m_normalizeVisibleArea ? "true" : "false") | 3488 |
3655 .arg(m_normalizeHybrid ? "true" : "false"); | 3489 s += QString("columnNormalization=\"%1\" ") |
3656 | 3490 .arg(m_normalization == NormalizeColumns ? "peak" : |
3491 m_normalization == NormalizeHybrid ? "hybrid" : "none"); | |
3492 | |
3493 // Old-style normalization attribute. We *don't* write out | |
3494 // normalizeHybrid here because the only release that would accept | |
3495 // it (Tony v1.0) has a totally different scale factor for | |
3496 // it. We'll just have to accept that session files from Tony | |
3497 // v2.0+ will look odd in Tony v1.0 | |
3498 | |
3499 s += QString("normalizeColumns=\"%1\" ") | |
3500 .arg(m_normalization == NormalizeColumns ? "true" : "false"); | |
3501 | |
3502 // And this applies to both old- and new-style attributes | |
3503 | |
3504 s += QString("normalizeVisibleArea=\"%1\" ") | |
3505 .arg(m_normalization == NormalizeVisibleArea ? "true" : "false"); | |
3506 | |
3657 Layer::toXml(stream, indent, extraAttributes + " " + s); | 3507 Layer::toXml(stream, indent, extraAttributes + " " + s); |
3658 } | 3508 } |
3659 | 3509 |
3660 void | 3510 void |
3661 SpectrogramLayer::setProperties(const QXmlAttributes &attributes) | 3511 SpectrogramLayer::setProperties(const QXmlAttributes &attributes) |
3716 | 3566 |
3717 BinDisplay binDisplay = (BinDisplay) | 3567 BinDisplay binDisplay = (BinDisplay) |
3718 attributes.value("binDisplay").toInt(&ok); | 3568 attributes.value("binDisplay").toInt(&ok); |
3719 if (ok) setBinDisplay(binDisplay); | 3569 if (ok) setBinDisplay(binDisplay); |
3720 | 3570 |
3721 bool normalizeColumns = | 3571 bool haveNewStyleNormalization = false; |
3722 (attributes.value("normalizeColumns").trimmed() == "true"); | 3572 |
3723 setNormalizeColumns(normalizeColumns); | 3573 QString columnNormalization = attributes.value("columnNormalization"); |
3574 | |
3575 if (columnNormalization != "") { | |
3576 | |
3577 haveNewStyleNormalization = true; | |
3578 | |
3579 if (columnNormalization == "peak") { | |
3580 setNormalization(NormalizeColumns); | |
3581 } else if (columnNormalization == "hybrid") { | |
3582 setNormalization(NormalizeHybrid); | |
3583 } else if (columnNormalization == "none") { | |
3584 // do nothing | |
3585 } else { | |
3586 cerr << "NOTE: Unknown or unsupported columnNormalization attribute \"" | |
3587 << columnNormalization << "\"" << endl; | |
3588 } | |
3589 } | |
3590 | |
3591 if (!haveNewStyleNormalization) { | |
3592 | |
3593 bool normalizeColumns = | |
3594 (attributes.value("normalizeColumns").trimmed() == "true"); | |
3595 if (normalizeColumns) { | |
3596 setNormalization(NormalizeColumns); | |
3597 } | |
3598 | |
3599 bool normalizeHybrid = | |
3600 (attributes.value("normalizeHybrid").trimmed() == "true"); | |
3601 if (normalizeHybrid) { | |
3602 setNormalization(NormalizeHybrid); | |
3603 } | |
3604 } | |
3724 | 3605 |
3725 bool normalizeVisibleArea = | 3606 bool normalizeVisibleArea = |
3726 (attributes.value("normalizeVisibleArea").trimmed() == "true"); | 3607 (attributes.value("normalizeVisibleArea").trimmed() == "true"); |
3727 setNormalizeVisibleArea(normalizeVisibleArea); | 3608 if (normalizeVisibleArea) { |
3728 | 3609 setNormalization(NormalizeVisibleArea); |
3729 bool normalizeHybrid = | 3610 } |
3730 (attributes.value("normalizeHybrid").trimmed() == "true"); | 3611 |
3731 setNormalizeHybrid(normalizeHybrid); | 3612 if (!haveNewStyleNormalization && m_normalization == NormalizeHybrid) { |
3732 } | 3613 // Tony v1.0 is (and hopefully will remain!) the only released |
3733 | 3614 // SV-a-like to use old-style attributes when saving sessions |
3615 // that ask for hybrid normalization. It saves them with the | |
3616 // wrong gain factor, so hack in a fix for that here -- this | |
3617 // gives us backward but not forward compatibility. | |
3618 setGain(m_gain / float(m_fftSize / 2)); | |
3619 } | |
3620 } | |
3621 |