Mercurial > hg > svgui
comparison layer/SpectrumLayer.cpp @ 1382:2df1af7ac752 spectrogramparam
Add oversampling option to spectrum as well
author | Chris Cannam |
---|---|
date | Wed, 07 Nov 2018 11:37:51 +0000 |
parents | d79e21855aef |
children | 37e9d6a1e00c |
comparison
equal
deleted
inserted
replaced
1381:2f4476993ae6 | 1382:2df1af7ac752 |
---|---|
37 m_channel(-1), | 37 m_channel(-1), |
38 m_channelSet(false), | 38 m_channelSet(false), |
39 m_windowSize(4096), | 39 m_windowSize(4096), |
40 m_windowType(HanningWindow), | 40 m_windowType(HanningWindow), |
41 m_windowHopLevel(3), | 41 m_windowHopLevel(3), |
42 m_oversampling(1), | |
42 m_showPeaks(false), | 43 m_showPeaks(false), |
43 m_newFFTNeeded(true) | 44 m_newFFTNeeded(true) |
44 { | 45 { |
45 Preferences *prefs = Preferences::getInstance(); | 46 Preferences *prefs = Preferences::getInstance(); |
46 connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)), | 47 connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)), |
110 | 111 |
111 if (!m_originModel) { | 112 if (!m_originModel) { |
112 return; | 113 return; |
113 } | 114 } |
114 | 115 |
116 int fftSize = getFFTSize(); | |
117 | |
115 FFTModel *newFFT = new FFTModel(m_originModel, | 118 FFTModel *newFFT = new FFTModel(m_originModel, |
116 m_channel, | 119 m_channel, |
117 m_windowType, | 120 m_windowType, |
118 m_windowSize, | 121 m_windowSize, |
119 getWindowIncrement(), | 122 getWindowIncrement(), |
120 m_windowSize); | 123 fftSize); |
121 | 124 |
122 setSliceableModel(newFFT); | 125 setSliceableModel(newFFT); |
123 | 126 |
124 m_biasCurve.clear(); | 127 m_biasCurve.clear(); |
125 for (int i = 0; i < m_windowSize; ++i) { | 128 for (int i = 0; i < fftSize; ++i) { |
126 m_biasCurve.push_back(1.f / (float(m_windowSize)/2.f)); | 129 m_biasCurve.push_back(1.f / (float(fftSize)/2.f)); |
127 } | 130 } |
128 | 131 |
129 m_newFFTNeeded = false; | 132 m_newFFTNeeded = false; |
130 } | 133 } |
131 | 134 |
133 SpectrumLayer::getProperties() const | 136 SpectrumLayer::getProperties() const |
134 { | 137 { |
135 PropertyList list = SliceLayer::getProperties(); | 138 PropertyList list = SliceLayer::getProperties(); |
136 list.push_back("Window Size"); | 139 list.push_back("Window Size"); |
137 list.push_back("Window Increment"); | 140 list.push_back("Window Increment"); |
141 list.push_back("Oversampling"); | |
138 list.push_back("Show Peak Frequencies"); | 142 list.push_back("Show Peak Frequencies"); |
139 return list; | 143 return list; |
140 } | 144 } |
141 | 145 |
142 QString | 146 QString |
143 SpectrumLayer::getPropertyLabel(const PropertyName &name) const | 147 SpectrumLayer::getPropertyLabel(const PropertyName &name) const |
144 { | 148 { |
145 if (name == "Window Size") return tr("Window Size"); | 149 if (name == "Window Size") return tr("Window Size"); |
146 if (name == "Window Increment") return tr("Window Overlap"); | 150 if (name == "Window Increment") return tr("Window Overlap"); |
151 if (name == "Oversampling") return tr("Oversampling"); | |
147 if (name == "Show Peak Frequencies") return tr("Show Peak Frequencies"); | 152 if (name == "Show Peak Frequencies") return tr("Show Peak Frequencies"); |
148 return SliceLayer::getPropertyLabel(name); | 153 return SliceLayer::getPropertyLabel(name); |
149 } | 154 } |
150 | 155 |
151 QString | 156 QString |
158 Layer::PropertyType | 163 Layer::PropertyType |
159 SpectrumLayer::getPropertyType(const PropertyName &name) const | 164 SpectrumLayer::getPropertyType(const PropertyName &name) const |
160 { | 165 { |
161 if (name == "Window Size") return ValueProperty; | 166 if (name == "Window Size") return ValueProperty; |
162 if (name == "Window Increment") return ValueProperty; | 167 if (name == "Window Increment") return ValueProperty; |
168 if (name == "Oversampling") return ValueProperty; | |
163 if (name == "Show Peak Frequencies") return ToggleProperty; | 169 if (name == "Show Peak Frequencies") return ToggleProperty; |
164 return SliceLayer::getPropertyType(name); | 170 return SliceLayer::getPropertyType(name); |
165 } | 171 } |
166 | 172 |
167 QString | 173 QString |
168 SpectrumLayer::getPropertyGroupName(const PropertyName &name) const | 174 SpectrumLayer::getPropertyGroupName(const PropertyName &name) const |
169 { | 175 { |
170 if (name == "Window Size" || | 176 if (name == "Window Size" || |
171 name == "Window Increment") return tr("Window"); | 177 name == "Window Increment" || |
178 name == "Oversampling") return tr("Window"); | |
172 if (name == "Show Peak Frequencies") return tr("Bins"); | 179 if (name == "Show Peak Frequencies") return tr("Bins"); |
173 return SliceLayer::getPropertyGroupName(name); | 180 return SliceLayer::getPropertyGroupName(name); |
174 } | 181 } |
175 | 182 |
176 int | 183 int |
200 *max = 5; | 207 *max = 5; |
201 *deflt = 2; | 208 *deflt = 2; |
202 | 209 |
203 val = m_windowHopLevel; | 210 val = m_windowHopLevel; |
204 | 211 |
212 } else if (name == "Oversampling") { | |
213 | |
214 *min = 0; | |
215 *max = 3; | |
216 *deflt = 0; | |
217 | |
218 val = 0; | |
219 int ov = m_oversampling; | |
220 while (ov > 1) { ov >>= 1; val ++; } | |
221 | |
205 } else if (name == "Show Peak Frequencies") { | 222 } else if (name == "Show Peak Frequencies") { |
206 | 223 |
207 return m_showPeaks ? 1 : 0; | 224 return m_showPeaks ? 1 : 0; |
208 | 225 |
209 } else { | 226 } else { |
230 case 3: return tr("75 %"); | 247 case 3: return tr("75 %"); |
231 case 4: return tr("87.5 %"); | 248 case 4: return tr("87.5 %"); |
232 case 5: return tr("93.75 %"); | 249 case 5: return tr("93.75 %"); |
233 } | 250 } |
234 } | 251 } |
252 if (name == "Oversampling") { | |
253 switch (value) { | |
254 default: | |
255 case 0: return tr("1x"); | |
256 case 1: return tr("2x"); | |
257 case 2: return tr("4x"); | |
258 case 3: return tr("8x"); | |
259 } | |
260 } | |
235 return SliceLayer::getPropertyValueLabel(name, value); | 261 return SliceLayer::getPropertyValueLabel(name, value); |
236 } | 262 } |
237 | 263 |
238 RangeMapper * | 264 RangeMapper * |
239 SpectrumLayer::getNewPropertyRangeMapper(const PropertyName &name) const | 265 SpectrumLayer::getNewPropertyRangeMapper(const PropertyName &name) const |
246 { | 272 { |
247 if (name == "Window Size") { | 273 if (name == "Window Size") { |
248 setWindowSize(32 << value); | 274 setWindowSize(32 << value); |
249 } else if (name == "Window Increment") { | 275 } else if (name == "Window Increment") { |
250 setWindowHopLevel(value); | 276 setWindowHopLevel(value); |
277 } else if (name == "Oversampling") { | |
278 setOversampling(1 << value); | |
251 } else if (name == "Show Peak Frequencies") { | 279 } else if (name == "Show Peak Frequencies") { |
252 setShowPeaks(value ? true : false); | 280 setShowPeaks(value ? true : false); |
253 } else { | 281 } else { |
254 SliceLayer::setProperty(name, value); | 282 SliceLayer::setProperty(name, value); |
255 } | 283 } |
281 m_newFFTNeeded = true; | 309 m_newFFTNeeded = true; |
282 emit layerParametersChanged(); | 310 emit layerParametersChanged(); |
283 } | 311 } |
284 | 312 |
285 void | 313 void |
314 SpectrumLayer::setOversampling(int oversampling) | |
315 { | |
316 if (m_oversampling == oversampling) return; | |
317 m_oversampling = oversampling; | |
318 m_newFFTNeeded = true; | |
319 emit layerParametersChanged(); | |
320 } | |
321 | |
322 int | |
323 SpectrumLayer::getOversampling() const | |
324 { | |
325 return m_oversampling; | |
326 } | |
327 | |
328 void | |
286 SpectrumLayer::setShowPeaks(bool show) | 329 SpectrumLayer::setShowPeaks(bool show) |
287 { | 330 { |
288 if (m_showPeaks == show) return; | 331 if (m_showPeaks == show) return; |
289 m_showPeaks = show; | 332 m_showPeaks = show; |
290 emit layerParametersChanged(); | 333 emit layerParametersChanged(); |
292 | 335 |
293 void | 336 void |
294 SpectrumLayer::preferenceChanged(PropertyContainer::PropertyName name) | 337 SpectrumLayer::preferenceChanged(PropertyContainer::PropertyName name) |
295 { | 338 { |
296 if (name == "Window Type") { | 339 if (name == "Window Type") { |
297 setWindowType(Preferences::getInstance()->getWindowType()); | 340 auto type = Preferences::getInstance()->getWindowType(); |
341 SVDEBUG << "SpectrumLayer::preferenceChanged: Window type changed to " | |
342 << type << endl; | |
343 setWindowType(type); | |
298 return; | 344 return; |
299 } | 345 } |
300 } | 346 } |
301 | 347 |
302 double | 348 double |
516 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); | 562 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); |
517 | 563 |
518 QString binstr; | 564 QString binstr; |
519 QString hzstr; | 565 QString hzstr; |
520 int minfreq = int(lrint((minbin * m_sliceableModel->getSampleRate()) / | 566 int minfreq = int(lrint((minbin * m_sliceableModel->getSampleRate()) / |
521 m_windowSize)); | 567 getFFTSize())); |
522 int maxfreq = int(lrint((std::max(maxbin, minbin) | 568 int maxfreq = int(lrint((std::max(maxbin, minbin) |
523 * m_sliceableModel->getSampleRate()) / | 569 * m_sliceableModel->getSampleRate()) / |
524 m_windowSize)); | 570 getFFTSize())); |
525 | 571 |
526 if (maxbin != minbin) { | 572 if (maxbin != minbin) { |
527 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); | 573 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); |
528 } else { | 574 } else { |
529 binstr = QString("%1").arg(minbin+1); | 575 binstr = QString("%1").arg(minbin+1); |
600 } | 646 } |
601 | 647 |
602 FFTModel *fft = dynamic_cast<FFTModel *> | 648 FFTModel *fft = dynamic_cast<FFTModel *> |
603 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); | 649 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); |
604 | 650 |
605 double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj | 651 double thresh = (pow(10, -6) / m_gain) * (getFFTSize() / 2.0); // -60dB adj |
606 | 652 |
607 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; | 653 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; |
608 int scaleHeight = getHorizontalScaleHeight(v, paint); | 654 int scaleHeight = getHorizontalScaleHeight(v, paint); |
609 | 655 |
610 if (fft && m_showPeaks) { | 656 if (fft && m_showPeaks) { |
744 SpectrumLayer::toXml(QTextStream &stream, | 790 SpectrumLayer::toXml(QTextStream &stream, |
745 QString indent, QString extraAttributes) const | 791 QString indent, QString extraAttributes) const |
746 { | 792 { |
747 QString s = QString("windowSize=\"%1\" " | 793 QString s = QString("windowSize=\"%1\" " |
748 "windowHopLevel=\"%2\" " | 794 "windowHopLevel=\"%2\" " |
749 "showPeaks=\"%3\" ") | 795 "oversampling=\"%3\" " |
796 "showPeaks=\"%4\" ") | |
750 .arg(m_windowSize) | 797 .arg(m_windowSize) |
751 .arg(m_windowHopLevel) | 798 .arg(m_windowHopLevel) |
799 .arg(m_oversampling) | |
752 .arg(m_showPeaks ? "true" : "false"); | 800 .arg(m_showPeaks ? "true" : "false"); |
753 | 801 |
754 SliceLayer::toXml(stream, indent, extraAttributes + " " + s); | 802 SliceLayer::toXml(stream, indent, extraAttributes + " " + s); |
755 } | 803 } |
756 | 804 |
765 if (ok) setWindowSize(windowSize); | 813 if (ok) setWindowSize(windowSize); |
766 | 814 |
767 int windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok); | 815 int windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok); |
768 if (ok) setWindowHopLevel(windowHopLevel); | 816 if (ok) setWindowHopLevel(windowHopLevel); |
769 | 817 |
818 int oversampling = attributes.value("oversampling").toUInt(&ok); | |
819 if (ok) setOversampling(oversampling); | |
820 | |
770 bool showPeaks = (attributes.value("showPeaks").trimmed() == "true"); | 821 bool showPeaks = (attributes.value("showPeaks").trimmed() == "true"); |
771 setShowPeaks(showPeaks); | 822 setShowPeaks(showPeaks); |
772 } | 823 } |
773 | 824 |
774 | 825 |