Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 120:8dfa20f1c70a
* some work on scaling and zooming for spectrogram
author | Chris Cannam |
---|---|
date | Wed, 19 Jul 2006 16:55:29 +0000 |
parents | 508276c923ba |
children | 7363cacf7de0 |
comparison
equal
deleted
inserted
replaced
119:508276c923ba | 120:8dfa20f1c70a |
---|---|
54 m_colourScale(dBColourScale), | 54 m_colourScale(dBColourScale), |
55 m_colourScheme(DefaultColours), | 55 m_colourScheme(DefaultColours), |
56 m_frequencyScale(LinearFrequencyScale), | 56 m_frequencyScale(LinearFrequencyScale), |
57 m_binDisplay(AllBins), | 57 m_binDisplay(AllBins), |
58 m_normalizeColumns(false), | 58 m_normalizeColumns(false), |
59 m_normalizeVisibleArea(false), | |
59 m_updateTimer(0), | 60 m_updateTimer(0), |
60 m_candidateFillStartFrame(0), | 61 m_candidateFillStartFrame(0), |
61 m_exiting(false) | 62 m_exiting(false) |
62 { | 63 { |
63 if (config == MelodicRange) { | 64 if (config == MelodicRange) { |
123 list.push_back("Colour Scale"); | 124 list.push_back("Colour Scale"); |
124 // list.push_back("Window Type"); | 125 // list.push_back("Window Type"); |
125 list.push_back("Window Size"); | 126 list.push_back("Window Size"); |
126 list.push_back("Window Increment"); | 127 list.push_back("Window Increment"); |
127 list.push_back("Normalize Columns"); | 128 list.push_back("Normalize Columns"); |
129 list.push_back("Normalize Visible Area"); | |
128 list.push_back("Bin Display"); | 130 list.push_back("Bin Display"); |
129 list.push_back("Threshold"); | 131 list.push_back("Threshold"); |
130 list.push_back("Gain"); | 132 list.push_back("Gain"); |
131 list.push_back("Colour Rotation"); | 133 list.push_back("Colour Rotation"); |
132 list.push_back("Min Frequency"); | 134 list.push_back("Min Frequency"); |
143 if (name == "Colour Scale") return tr("Colour Scale"); | 145 if (name == "Colour Scale") return tr("Colour Scale"); |
144 if (name == "Window Type") return tr("Window Type"); | 146 if (name == "Window Type") return tr("Window Type"); |
145 if (name == "Window Size") return tr("Window Size"); | 147 if (name == "Window Size") return tr("Window Size"); |
146 if (name == "Window Increment") return tr("Window Overlap"); | 148 if (name == "Window Increment") return tr("Window Overlap"); |
147 if (name == "Normalize Columns") return tr("Normalize Columns"); | 149 if (name == "Normalize Columns") return tr("Normalize Columns"); |
150 if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); | |
148 if (name == "Bin Display") return tr("Bin Display"); | 151 if (name == "Bin Display") return tr("Bin Display"); |
149 if (name == "Threshold") return tr("Threshold"); | 152 if (name == "Threshold") return tr("Threshold"); |
150 if (name == "Gain") return tr("Gain"); | 153 if (name == "Gain") return tr("Gain"); |
151 if (name == "Colour Rotation") return tr("Colour Rotation"); | 154 if (name == "Colour Rotation") return tr("Colour Rotation"); |
152 if (name == "Min Frequency") return tr("Min Frequency"); | 155 if (name == "Min Frequency") return tr("Min Frequency"); |
160 SpectrogramLayer::getPropertyType(const PropertyName &name) const | 163 SpectrogramLayer::getPropertyType(const PropertyName &name) const |
161 { | 164 { |
162 if (name == "Gain") return RangeProperty; | 165 if (name == "Gain") return RangeProperty; |
163 if (name == "Colour Rotation") return RangeProperty; | 166 if (name == "Colour Rotation") return RangeProperty; |
164 if (name == "Normalize Columns") return ToggleProperty; | 167 if (name == "Normalize Columns") return ToggleProperty; |
168 if (name == "Normalize Visible Area") return ToggleProperty; | |
165 if (name == "Threshold") return RangeProperty; | 169 if (name == "Threshold") return RangeProperty; |
166 if (name == "Zero Padding") return ToggleProperty; | 170 if (name == "Zero Padding") return ToggleProperty; |
167 return ValueProperty; | 171 return ValueProperty; |
168 } | 172 } |
169 | 173 |
177 if (name == "Colour" || | 181 if (name == "Colour" || |
178 name == "Gain" || | 182 name == "Gain" || |
179 name == "Threshold" || | 183 name == "Threshold" || |
180 name == "Colour Rotation") return tr("Colour"); | 184 name == "Colour Rotation") return tr("Colour"); |
181 if (name == "Normalize Columns" || | 185 if (name == "Normalize Columns" || |
186 name == "Normalize Visible Area" || | |
182 name == "Bin Display" || | 187 name == "Bin Display" || |
183 name == "Colour Scale") return tr("Scale"); | 188 name == "Colour Scale") return tr("Scale"); |
184 if (name == "Max Frequency" || | 189 if (name == "Max Frequency" || |
185 name == "Min Frequency" || | 190 name == "Min Frequency" || |
186 name == "Frequency Scale" || | 191 name == "Frequency Scale" || |
316 deft = (int)m_binDisplay; | 321 deft = (int)m_binDisplay; |
317 | 322 |
318 } else if (name == "Normalize Columns") { | 323 } else if (name == "Normalize Columns") { |
319 | 324 |
320 deft = (m_normalizeColumns ? 1 : 0); | 325 deft = (m_normalizeColumns ? 1 : 0); |
326 | |
327 } else if (name == "Normalize Visible Area") { | |
328 | |
329 deft = (m_normalizeVisibleArea ? 1 : 0); | |
321 | 330 |
322 } else { | 331 } else { |
323 deft = Layer::getPropertyRangeAndValue(name, min, max); | 332 deft = Layer::getPropertyRangeAndValue(name, min, max); |
324 } | 333 } |
325 | 334 |
509 case 1: setBinDisplay(PeakBins); break; | 518 case 1: setBinDisplay(PeakBins); break; |
510 case 2: setBinDisplay(PeakFrequencies); break; | 519 case 2: setBinDisplay(PeakFrequencies); break; |
511 } | 520 } |
512 } else if (name == "Normalize Columns") { | 521 } else if (name == "Normalize Columns") { |
513 setNormalizeColumns(value ? true : false); | 522 setNormalizeColumns(value ? true : false); |
523 } else if (name == "Normalize Visible Area") { | |
524 setNormalizeVisibleArea(value ? true : false); | |
514 } | 525 } |
515 } | 526 } |
516 | 527 |
517 void | 528 void |
518 SpectrogramLayer::invalidatePixmapCaches() | 529 SpectrogramLayer::invalidatePixmapCaches() |
818 | 829 |
819 bool | 830 bool |
820 SpectrogramLayer::getNormalizeColumns() const | 831 SpectrogramLayer::getNormalizeColumns() const |
821 { | 832 { |
822 return m_normalizeColumns; | 833 return m_normalizeColumns; |
834 } | |
835 | |
836 void | |
837 SpectrogramLayer::setNormalizeVisibleArea(bool n) | |
838 { | |
839 if (m_normalizeVisibleArea == n) return; | |
840 | |
841 invalidatePixmapCaches(); | |
842 invalidateMagnitudes(); | |
843 m_normalizeVisibleArea = n; | |
844 | |
845 emit layerParametersChanged(); | |
846 } | |
847 | |
848 bool | |
849 SpectrogramLayer::getNormalizeVisibleArea() const | |
850 { | |
851 return m_normalizeVisibleArea; | |
823 } | 852 } |
824 | 853 |
825 void | 854 void |
826 SpectrogramLayer::setLayerDormant(const View *v, bool dormant) | 855 SpectrogramLayer::setLayerDormant(const View *v, bool dormant) |
827 { | 856 { |
1064 unsigned char | 1093 unsigned char |
1065 SpectrogramLayer::getDisplayValue(View *v, float input) const | 1094 SpectrogramLayer::getDisplayValue(View *v, float input) const |
1066 { | 1095 { |
1067 int value; | 1096 int value; |
1068 | 1097 |
1069 //!!! for the moment we're always normalizing visible area | 1098 float min = 0.f; |
1070 float min = m_viewMags[v].getMin(); | 1099 float max = 1.f; |
1071 float max = m_viewMags[v].getMax(); | 1100 |
1101 if (m_normalizeVisibleArea) { | |
1102 min = m_viewMags[v].getMin(); | |
1103 max = m_viewMags[v].getMax(); | |
1104 } else if (!m_normalizeColumns) { | |
1105 if (m_colourScale == LinearColourScale || | |
1106 m_colourScale == MeterColourScale) { | |
1107 max = 0.1f; | |
1108 } | |
1109 } | |
1110 | |
1072 float thresh = -80.f; | 1111 float thresh = -80.f; |
1073 | 1112 |
1074 if (max == 0.f) max = 1.f; | 1113 if (max == 0.f) max = 1.f; |
1075 if (max == min) min = max - 0.0001f; | 1114 if (max == min) min = max - 0.0001f; |
1076 | 1115 |
1142 SpectrogramLayer::getInputForDisplayValue(unsigned char uc) const | 1181 SpectrogramLayer::getInputForDisplayValue(unsigned char uc) const |
1143 { | 1182 { |
1144 int value = uc; | 1183 int value = uc; |
1145 float input; | 1184 float input; |
1146 | 1185 |
1186 //!!! incorrect for normalizing visible area (and also out of date) | |
1187 | |
1147 switch (m_colourScale) { | 1188 switch (m_colourScale) { |
1148 | 1189 |
1149 default: | 1190 default: |
1150 case LinearColourScale: | 1191 case LinearColourScale: |
1151 input = float(value - 1) / 255.0 / (m_normalizeColumns ? 1 : 50); | 1192 input = float(value - 1) / 255.0 / (m_normalizeColumns ? 1 : 50); |
1994 | 2035 |
1995 QPainter cachePainter(&cache.pixmap); | 2036 QPainter cachePainter(&cache.pixmap); |
1996 cachePainter.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); | 2037 cachePainter.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); |
1997 cachePainter.end(); | 2038 cachePainter.end(); |
1998 | 2039 |
1999 if (!overallMagChanged) { | 2040 if (!m_normalizeVisibleArea || !overallMagChanged) { |
2000 | 2041 |
2001 cache.startFrame = startFrame; | 2042 cache.startFrame = startFrame; |
2002 cache.zoomLevel = zoomLevel; | 2043 cache.zoomLevel = zoomLevel; |
2003 | 2044 |
2004 if (cache.validArea.x() > 0) { | 2045 if (cache.validArea.x() > 0) { |
2028 // overallMagChanged | 2069 // overallMagChanged |
2029 cache.validArea = QRect(); | 2070 cache.validArea = QRect(); |
2030 v->update(); | 2071 v->update(); |
2031 } | 2072 } |
2032 | 2073 |
2074 QPoint localPos; | |
2075 | |
2076 if (v->shouldIlluminateLocalFeatures(this, localPos)) { | |
2077 | |
2078 std::cerr << "SpectrogramLayer: shouldIlluminateLocalFeatures(" | |
2079 << localPos.x() << "," << localPos.y() << ")" << std::endl; | |
2080 | |
2081 float s0, s1; | |
2082 float q0, q1; | |
2083 | |
2084 if (getXBinRange(v, localPos.x(), s0, s1) && | |
2085 getYBinRange(v, localPos.y(), q0, q1)) { | |
2086 | |
2087 int s0i = int(s0 + 0.001); | |
2088 int s1i = int(s1); | |
2089 | |
2090 int q0i = int(q0 + 0.001); | |
2091 int q1i = int(q1); | |
2092 | |
2093 int x0 = v->getXForFrame(s0i * getWindowIncrement()); | |
2094 int x1 = v->getXForFrame(s1i * getWindowIncrement() + 1); | |
2095 int y1 = yval[q0i]; | |
2096 int y0 = yval[q1i + 1]; | |
2097 | |
2098 std::cerr << "SpectrogramLayer::paint: illuminate " | |
2099 << x0 << "," << y1 << " -> " << x1 << "," << y0 << std::endl; | |
2100 | |
2101 paint.setPen(Qt::white); | |
2102 paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1); | |
2103 } | |
2104 } | |
2105 | |
2033 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2106 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2034 std::cerr << "SpectrogramLayer::paint() returning" << std::endl; | 2107 std::cerr << "SpectrogramLayer::paint() returning" << std::endl; |
2035 #endif | 2108 #endif |
2036 } | 2109 } |
2037 | 2110 |
2080 { | 2153 { |
2081 min = getEffectiveMinFrequency(); | 2154 min = getEffectiveMinFrequency(); |
2082 max = getEffectiveMaxFrequency(); | 2155 max = getEffectiveMaxFrequency(); |
2083 return true; | 2156 return true; |
2084 } | 2157 } |
2158 | |
2159 bool | |
2160 SpectrogramLayer::setDisplayExtents(float min, float max) | |
2161 { | |
2162 if (!m_model) return false; | |
2163 if (min < 0) min = 0; | |
2164 if (max > m_model->getSampleRate()/2) max = m_model->getSampleRate()/2; | |
2165 | |
2166 size_t minf = lrintf(min); | |
2167 size_t maxf = lrintf(max); | |
2168 | |
2169 if (m_minFrequency == minf && m_maxFrequency == maxf) return true; | |
2170 | |
2171 invalidatePixmapCaches(); | |
2172 invalidateMagnitudes(); | |
2173 | |
2174 m_minFrequency = minf; | |
2175 m_maxFrequency = maxf; | |
2176 | |
2177 emit layerParametersChanged(); | |
2178 | |
2179 return true; | |
2180 } | |
2085 | 2181 |
2086 bool | 2182 bool |
2087 SpectrogramLayer::snapToFeatureFrame(View *v, int &frame, | 2183 SpectrogramLayer::snapToFeatureFrame(View *v, int &frame, |
2088 size_t &resolution, | 2184 size_t &resolution, |
2089 SnapType snap) const | 2185 SnapType snap) const |
2327 { | 2423 { |
2328 if (!m_model || !m_model->isOK()) { | 2424 if (!m_model || !m_model->isOK()) { |
2329 return; | 2425 return; |
2330 } | 2426 } |
2331 | 2427 |
2428 //!!! cache this? | |
2429 | |
2332 int h = rect.height(), w = rect.width(); | 2430 int h = rect.height(), w = rect.width(); |
2333 | 2431 |
2334 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4); | 2432 int tickw = (m_frequencyScale == LogFrequencyScale ? 10 : 4); |
2335 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0); | 2433 int pkw = (m_frequencyScale == LogFrequencyScale ? 10 : 0); |
2336 | 2434 |
2391 float max = m_viewMags[v].getMax(); | 2489 float max = m_viewMags[v].getMax(); |
2392 | 2490 |
2393 float dBmin = AudioLevel::multiplier_to_dB(min); | 2491 float dBmin = AudioLevel::multiplier_to_dB(min); |
2394 float dBmax = AudioLevel::multiplier_to_dB(max); | 2492 float dBmax = AudioLevel::multiplier_to_dB(max); |
2395 | 2493 |
2396 if (dBmin < -80.f) dBmin = -80.f; | 2494 if (dBmax < -60.f) dBmax = -60.f; |
2495 else top = QString("%1").arg(lrintf(dBmax)); | |
2496 | |
2497 if (dBmin < dBmax - 60.f) dBmin = dBmax - 60.f; | |
2397 bottom = QString("%1").arg(lrintf(dBmin)); | 2498 bottom = QString("%1").arg(lrintf(dBmin)); |
2398 | |
2399 if (dBmax < -80.f) dBmax = -80.f; | |
2400 else top = QString("%1").arg(lrintf(dBmax)); | |
2401 | 2499 |
2402 //!!! & phase etc | 2500 //!!! & phase etc |
2403 | 2501 |
2404 if (m_colourScale != PhaseColourScale) { | 2502 if (m_colourScale != PhaseColourScale) { |
2405 paint.drawText((cw + 6 - paint.fontMetrics().width("dBFS")) / 2, | 2503 paint.drawText((cw + 6 - paint.fontMetrics().width("dBFS")) / 2, |
2446 | 2544 |
2447 if (i == 0) { | 2545 if (i == 0) { |
2448 lasty = y; | 2546 lasty = y; |
2449 lastdb = idb; | 2547 lastdb = idb; |
2450 } else if (i < ch - paint.fontMetrics().ascent() && | 2548 } else if (i < ch - paint.fontMetrics().ascent() && |
2549 idb != lastdb && | |
2451 ((abs(y - lasty) > textHeight && | 2550 ((abs(y - lasty) > textHeight && |
2452 idb % 10 == 0) || | 2551 idb % 10 == 0) || |
2453 (abs(y - lasty) > paint.fontMetrics().ascent() && | 2552 (abs(y - lasty) > paint.fontMetrics().ascent() && |
2454 idb % 5 == 0))) { | 2553 idb % 5 == 0))) { |
2455 paint.setPen(Qt::black); | 2554 paint.setPen(Qt::black); |