comparison layer/SpectrumLayer.cpp @ 193:57c2350a8c40

* Add slice layers (so you can display a slice of a colour 3d plot as if it were a spectrum) * Make spectrum layer a subclass of slice layer
author Chris Cannam
date Fri, 26 Jan 2007 16:59:57 +0000
parents 42118892f428
children 4a3bdde1ef13
comparison
equal deleted inserted replaced
192:fcc043f75c41 193:57c2350a8c40
20 #include "view/View.h" 20 #include "view/View.h"
21 #include "base/AudioLevel.h" 21 #include "base/AudioLevel.h"
22 #include "base/Preferences.h" 22 #include "base/Preferences.h"
23 #include "base/RangeMapper.h" 23 #include "base/RangeMapper.h"
24 24
25 #include <QPainter>
26 #include <QPainterPath>
27
28 SpectrumLayer::SpectrumLayer() : 25 SpectrumLayer::SpectrumLayer() :
29 m_model(0), 26 m_originModel(0),
30 m_channelMode(MixChannels),
31 m_channel(-1), 27 m_channel(-1),
32 m_channelSet(false), 28 m_channelSet(false),
33 m_colour(Qt::darkBlue),
34 m_energyScale(dBScale),
35 m_normalize(false),
36 m_gain(1.0),
37 m_windowSize(1024), 29 m_windowSize(1024),
38 m_windowType(HanningWindow), 30 m_windowType(HanningWindow),
39 m_windowHopLevel(2) 31 m_windowHopLevel(2)
40 { 32 {
41 Preferences *prefs = Preferences::getInstance(); 33 Preferences *prefs = Preferences::getInstance();
44 setWindowType(prefs->getWindowType()); 36 setWindowType(prefs->getWindowType());
45 } 37 }
46 38
47 SpectrumLayer::~SpectrumLayer() 39 SpectrumLayer::~SpectrumLayer()
48 { 40 {
49 for (size_t i = 0; i < m_fft.size(); ++i) delete m_fft[i]; 41 //!!! delete parent's model
42 // for (size_t i = 0; i < m_fft.size(); ++i) delete m_fft[i];
50 } 43 }
51 44
52 void 45 void
53 SpectrumLayer::setModel(DenseTimeValueModel *model) 46 SpectrumLayer::setModel(DenseTimeValueModel *model)
54 { 47 {
55 m_model = model; 48 if (m_originModel == model) return;
56 setupFFTs(); 49 m_originModel = model;
57 } 50 setupFFT();
58 51 }
59 void 52
60 SpectrumLayer::setupFFTs() 53 void
61 { 54 SpectrumLayer::setupFFT()
62 for (size_t i = 0; i < m_fft.size(); ++i) delete m_fft[i]; 55 {
63 m_fft.clear(); 56 FFTModel *oldFFT = dynamic_cast<FFTModel *>
64 57 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
65 int minChannel = m_channel, maxChannel = m_channel; 58
66 59 if (oldFFT) {
67 if (m_channel == -1 && 60 setSliceableModel(0);
68 m_channelMode != MixChannels) { 61 delete oldFFT;
69 minChannel = 0; 62 }
70 maxChannel = 0; 63
71 if (m_model->getChannelCount() > 1) { 64 FFTModel *newFFT = new FFTModel(m_originModel,
72 maxChannel = m_model->getChannelCount() - 1; 65 m_channel,
73 } 66 m_windowType,
74 } 67 m_windowSize,
75 68 getWindowIncrement(),
76 for (int c = minChannel; c <= maxChannel; ++c) { 69 m_windowSize,
77 70 true);
78 m_fft.push_back(new FFTModel(m_model, 71
79 c, 72 setSliceableModel(newFFT);
80 HanningWindow, 73
81 m_windowSize, 74 newFFT->resume();
82 getWindowIncrement(),
83 m_windowSize,
84 true));
85
86 if (m_channelSet) m_fft[m_fft.size()-1]->resume();
87 }
88 } 75 }
89 76
90 void 77 void
91 SpectrumLayer::setChannel(int channel) 78 SpectrumLayer::setChannel(int channel)
92 { 79 {
93 m_channelSet = true; 80 m_channelSet = true;
94 81
82 FFTModel *fft = dynamic_cast<FFTModel *>
83 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
84
95 if (m_channel == channel) { 85 if (m_channel == channel) {
96 for (size_t i = 0; i < m_fft.size(); ++i) { 86 if (fft) fft->resume();
97 m_fft[i]->resume();
98 }
99 return; 87 return;
100 } 88 }
101 89
102 m_channel = channel; 90 m_channel = channel;
103 91
104 if (!m_fft.empty()) setupFFTs(); 92 if (!fft) setupFFT();
105 93
106 emit layerParametersChanged(); 94 emit layerParametersChanged();
107 }
108
109 void
110 SpectrumLayer::paint(View *v, QPainter &paint, QRect rect) const
111 {
112 if (m_fft.empty()) return;
113 if (!m_channelSet) {
114 for (size_t i = 0; i < m_fft.size(); ++i) {
115 m_fft[i]->resume();
116 }
117 }
118
119 FFTModel *fft = m_fft[0]; //!!! for now
120
121 int windowIncrement = getWindowIncrement();
122
123 size_t f = v->getCentreFrame();
124
125 int w = (v->width() * 2) / 3;
126 int xorigin = (v->width() / 2) - (w / 2);
127
128 int h = (v->height() * 2) / 3;
129 int yorigin = (v->height() / 2) + (h / 2);
130
131 size_t column = f / windowIncrement;
132
133 paint.save();
134 paint.setPen(m_colour);
135 paint.setRenderHint(QPainter::Antialiasing, false);
136
137 QPainterPath path;
138 float thresh = -80.f;
139
140 for (size_t bin = 0; bin < fft->getHeight(); ++bin) {
141
142 float x = xorigin + (float(w) * bin) / fft->getHeight();
143 float mag;
144 if (m_normalize) {
145 mag = fft->getNormalizedMagnitudeAt(column, bin);
146 } else {
147 mag = fft->getMagnitudeAt(column, bin);
148 }
149 mag *= m_gain;
150 float y = 0.f;
151
152 switch (m_energyScale) {
153
154 case dBScale:
155 {
156 float db = thresh;
157 if (mag > 0.f) db = 10.f * log10f(mag);
158 if (db < thresh) db = thresh;
159 float val = (db - thresh) / -thresh;
160 y = yorigin - (float(h) * val);
161 break;
162 }
163
164 case MeterScale:
165 y = yorigin - AudioLevel::multiplier_to_preview(mag, h);
166 break;
167
168 default:
169 y = yorigin - (float(h) * mag);
170 break;
171 }
172
173 if (bin == 0) {
174 path.moveTo(x, y);
175 } else {
176 path.lineTo(x, y);
177 }
178 }
179
180 paint.drawPath(path);
181 paint.restore();
182
183 } 95 }
184 96
185 Layer::PropertyList 97 Layer::PropertyList
186 SpectrumLayer::getProperties() const 98 SpectrumLayer::getProperties() const
187 { 99 {
188 PropertyList list; 100 PropertyList list = SliceLayer::getProperties();
189 list.push_back("Colour");
190 list.push_back("Scale");
191 list.push_back("Normalize");
192 list.push_back("Gain");
193 list.push_back("Window Size"); 101 list.push_back("Window Size");
194 list.push_back("Window Increment"); 102 list.push_back("Window Increment");
195
196 if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) {
197 list.push_back("Channels");
198 }
199
200 return list; 103 return list;
201 } 104 }
202 105
203 QString 106 QString
204 SpectrumLayer::getPropertyLabel(const PropertyName &name) const 107 SpectrumLayer::getPropertyLabel(const PropertyName &name) const
205 { 108 {
206 if (name == "Colour") return tr("Colour");
207 if (name == "Energy Scale") return tr("Scale");
208 if (name == "Channels") return tr("Channels");
209 if (name == "Window Size") return tr("Window Size"); 109 if (name == "Window Size") return tr("Window Size");
210 if (name == "Window Increment") return tr("Window Overlap"); 110 if (name == "Window Increment") return tr("Window Overlap");
211 if (name == "Normalize") return tr("Normalize"); 111 return SliceLayer::getPropertyLabel(name);
212 if (name == "Gain") return tr("Gain");
213 return "";
214 } 112 }
215 113
216 Layer::PropertyType 114 Layer::PropertyType
217 SpectrumLayer::getPropertyType(const PropertyName &name) const 115 SpectrumLayer::getPropertyType(const PropertyName &name) const
218 { 116 {
219 if (name == "Gain") return RangeProperty; 117 if (name == "Window Size") return ValueProperty;
220 if (name == "Normalize") return ToggleProperty; 118 if (name == "Window Increment") return ValueProperty;
221 return ValueProperty; 119 return SliceLayer::getPropertyType(name);
222 } 120 }
223 121
224 QString 122 QString
225 SpectrumLayer::getPropertyGroupName(const PropertyName &name) const 123 SpectrumLayer::getPropertyGroupName(const PropertyName &name) const
226 { 124 {
227 if (name == "Window Size" || 125 if (name == "Window Size" ||
228 name == "Window Increment") return tr("Window"); 126 name == "Window Increment") return tr("Window");
229 if (name == "Scale" || 127 return SliceLayer::getPropertyGroupName(name);
230 name == "Normalize" ||
231 name == "Gain") return tr("Energy Scale");
232 return QString();
233 } 128 }
234 129
235 int 130 int
236 SpectrumLayer::getPropertyRangeAndValue(const PropertyName &name, 131 SpectrumLayer::getPropertyRangeAndValue(const PropertyName &name,
237 int *min, int *max) const 132 int *min, int *max) const
240 135
241 int garbage0, garbage1; 136 int garbage0, garbage1;
242 if (!min) min = &garbage0; 137 if (!min) min = &garbage0;
243 if (!max) max = &garbage1; 138 if (!max) max = &garbage1;
244 139
245 if (name == "Gain") { 140 if (name == "Window Size") {
246
247 *min = -50;
248 *max = 50;
249
250 deft = lrint(log10(m_gain) * 20.0);
251 if (deft < *min) deft = *min;
252 if (deft > *max) deft = *max;
253
254 } else if (name == "Normalize") {
255
256 deft = (m_normalize ? 1 : 0);
257
258 } else if (name == "Colour") {
259
260 *min = 0;
261 *max = 5;
262
263 if (m_colour == Qt::black) deft = 0;
264 else if (m_colour == Qt::darkRed) deft = 1;
265 else if (m_colour == Qt::darkBlue) deft = 2;
266 else if (m_colour == Qt::darkGreen) deft = 3;
267 else if (m_colour == QColor(200, 50, 255)) deft = 4;
268 else if (m_colour == QColor(255, 150, 50)) deft = 5;
269
270 } else if (name == "Channels") {
271
272 *min = 0;
273 *max = 2;
274 if (m_channelMode == MixChannels) deft = 1;
275 else if (m_channelMode == OverlayChannels) deft = 2;
276 else deft = 0;
277
278 } else if (name == "Scale") {
279
280 *min = 0;
281 *max = 2;
282
283 deft = (int)m_energyScale;
284
285 } else if (name == "Window Size") {
286 141
287 *min = 0; 142 *min = 0;
288 *max = 10; 143 *max = 10;
289 144
290 deft = 0; 145 deft = 0;
297 *max = 5; 152 *max = 5;
298 153
299 deft = m_windowHopLevel; 154 deft = m_windowHopLevel;
300 155
301 } else { 156 } else {
302 deft = Layer::getPropertyRangeAndValue(name, min, max); 157
158 deft = SliceLayer::getPropertyRangeAndValue(name, min, max);
303 } 159 }
304 160
305 return deft; 161 return deft;
306 } 162 }
307 163
308 QString 164 QString
309 SpectrumLayer::getPropertyValueLabel(const PropertyName &name, 165 SpectrumLayer::getPropertyValueLabel(const PropertyName &name,
310 int value) const 166 int value) const
311 { 167 {
312 if (name == "Colour") {
313 switch (value) {
314 default:
315 case 0: return tr("Black");
316 case 1: return tr("Red");
317 case 2: return tr("Blue");
318 case 3: return tr("Green");
319 case 4: return tr("Purple");
320 case 5: return tr("Orange");
321 }
322 }
323 if (name == "Scale") {
324 switch (value) {
325 default:
326 case 0: return tr("Linear");
327 case 1: return tr("Meter");
328 case 2: return tr("dB");
329 }
330 }
331 if (name == "Channels") {
332 switch (value) {
333 default:
334 case 0: return tr("Separate");
335 case 1: return tr("Mean");
336 case 2: return tr("Overlay");
337 }
338 }
339 if (name == "Window Size") { 168 if (name == "Window Size") {
340 return QString("%1").arg(32 << value); 169 return QString("%1").arg(32 << value);
341 } 170 }
342 if (name == "Window Increment") { 171 if (name == "Window Increment") {
343 switch (value) { 172 switch (value) {
348 case 3: return tr("75 %"); 177 case 3: return tr("75 %");
349 case 4: return tr("87.5 %"); 178 case 4: return tr("87.5 %");
350 case 5: return tr("93.75 %"); 179 case 5: return tr("93.75 %");
351 } 180 }
352 } 181 }
353 return tr("<unknown>"); 182 return SliceLayer::getPropertyValueLabel(name, value);
354 } 183 }
355 184
356 RangeMapper * 185 RangeMapper *
357 SpectrumLayer::getNewPropertyRangeMapper(const PropertyName &name) const 186 SpectrumLayer::getNewPropertyRangeMapper(const PropertyName &name) const
358 { 187 {
359 if (name == "Gain") { 188 return SliceLayer::getNewPropertyRangeMapper(name);
360 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
361 }
362 return 0;
363 } 189 }
364 190
365 void 191 void
366 SpectrumLayer::setProperty(const PropertyName &name, int value) 192 SpectrumLayer::setProperty(const PropertyName &name, int value)
367 { 193 {
368 if (name == "Gain") { 194 if (name == "Window Size") {
369 setGain(pow(10, float(value)/20.0));
370 } else if (name == "Colour") {
371 switch (value) {
372 default:
373 case 0: setBaseColour(Qt::black); break;
374 case 1: setBaseColour(Qt::darkRed); break;
375 case 2: setBaseColour(Qt::darkBlue); break;
376 case 3: setBaseColour(Qt::darkGreen); break;
377 case 4: setBaseColour(QColor(200, 50, 255)); break;
378 case 5: setBaseColour(QColor(255, 150, 50)); break;
379 }
380 } else if (name == "Channels") {
381 if (value == 1) setChannelMode(MixChannels);
382 else if (value == 2) setChannelMode(OverlayChannels);
383 else setChannelMode(SeparateChannels);
384 } else if (name == "Scale") {
385 switch (value) {
386 default:
387 case 0: setEnergyScale(LinearScale); break;
388 case 1: setEnergyScale(MeterScale); break;
389 case 2: setEnergyScale(dBScale); break;
390 }
391 } else if (name == "Window Size") {
392 setWindowSize(32 << value); 195 setWindowSize(32 << value);
393 } else if (name == "Window Increment") { 196 } else if (name == "Window Increment") {
394 setWindowHopLevel(value); 197 setWindowHopLevel(value);
395 } else if (name == "Normalize") { 198 } else {
396 setNormalize(value ? true : false); 199 SliceLayer::setProperty(name, value);
397 } 200 }
398 }
399
400 void
401 SpectrumLayer::setBaseColour(QColor colour)
402 {
403 if (m_colour == colour) return;
404 m_colour = colour;
405 emit layerParametersChanged();
406 }
407
408 void
409 SpectrumLayer::setChannelMode(ChannelMode channelMode)
410 {
411 if (m_channelMode == channelMode) return;
412 m_channelMode = channelMode;
413 emit layerParametersChanged();
414 }
415
416 void
417 SpectrumLayer::setEnergyScale(EnergyScale scale)
418 {
419 if (m_energyScale == scale) return;
420 m_energyScale = scale;
421 emit layerParametersChanged();
422 } 201 }
423 202
424 void 203 void
425 SpectrumLayer::setWindowSize(size_t ws) 204 SpectrumLayer::setWindowSize(size_t ws)
426 { 205 {
427 if (m_windowSize == ws) return; 206 if (m_windowSize == ws) return;
428 m_windowSize = ws; 207 m_windowSize = ws;
429 setupFFTs(); 208 setupFFT();
430 emit layerParametersChanged(); 209 emit layerParametersChanged();
431 } 210 }
432 211
433 void 212 void
434 SpectrumLayer::setWindowHopLevel(size_t v) 213 SpectrumLayer::setWindowHopLevel(size_t v)
435 { 214 {
436 if (m_windowHopLevel == v) return; 215 if (m_windowHopLevel == v) return;
437 m_windowHopLevel = v; 216 m_windowHopLevel = v;
438 setupFFTs(); 217 setupFFT();
439 emit layerParametersChanged(); 218 emit layerParametersChanged();
440 } 219 }
441 220
442 void 221 void
443 SpectrumLayer::setWindowType(WindowType w) 222 SpectrumLayer::setWindowType(WindowType w)
444 { 223 {
445 if (m_windowType == w) return; 224 if (m_windowType == w) return;
446 m_windowType = w; 225 m_windowType = w;
447 setupFFTs(); 226 setupFFT();
448 emit layerParametersChanged();
449 }
450
451 void
452 SpectrumLayer::setNormalize(bool n)
453 {
454 if (m_normalize == n) return;
455 m_normalize = n;
456 emit layerParametersChanged();
457 }
458
459 void
460 SpectrumLayer::setGain(float gain)
461 {
462 if (m_gain == gain) return;
463 m_gain = gain;
464 emit layerParametersChanged(); 227 emit layerParametersChanged();
465 } 228 }
466 229
467 void 230 void
468 SpectrumLayer::preferenceChanged(PropertyContainer::PropertyName name) 231 SpectrumLayer::preferenceChanged(PropertyContainer::PropertyName name)
476 QString 239 QString
477 SpectrumLayer::toXmlString(QString indent, QString extraAttributes) const 240 SpectrumLayer::toXmlString(QString indent, QString extraAttributes) const
478 { 241 {
479 QString s; 242 QString s;
480 243
481 s += QString("colour=\"%1\" " 244 s += QString("windowSize=\"%1\" "
482 "channelMode=\"%2\" " 245 "windowHopLevel=\"%2\"")
483 "channel=\"%3\" "
484 "energyScale=\"%4\" "
485 "windowSize=\"%5\" "
486 "windowHopLevel=\"%6\" "
487 "gain=\"%7\" "
488 "normalize=\"%8\"")
489 .arg(encodeColour(m_colour))
490 .arg(m_channelMode)
491 .arg(m_channel)
492 .arg(m_energyScale)
493 .arg(m_windowSize) 246 .arg(m_windowSize)
494 .arg(m_windowHopLevel) 247 .arg(m_windowHopLevel);
495 .arg(m_gain) 248
496 .arg(m_normalize ? "true" : "false"); 249 return SliceLayer::toXmlString(indent, extraAttributes + " " + s);
497
498 return Layer::toXmlString(indent, extraAttributes + " " + s);
499 } 250 }
500 251
501 void 252 void
502 SpectrumLayer::setProperties(const QXmlAttributes &attributes) 253 SpectrumLayer::setProperties(const QXmlAttributes &attributes)
503 { 254 {
504 bool ok = false; 255 bool ok = false;
505
506 QString colourSpec = attributes.value("colour");
507 if (colourSpec != "") {
508 QColor colour(colourSpec);
509 if (colour.isValid()) {
510 setBaseColour(QColor(colourSpec));
511 }
512 }
513
514 ChannelMode channelMode = (ChannelMode)
515 attributes.value("channelMode").toInt(&ok);
516 if (ok) setChannelMode(channelMode);
517
518 int channel = attributes.value("channel").toInt(&ok);
519 if (ok) setChannel(channel);
520
521 EnergyScale scale = (EnergyScale)
522 attributes.value("energyScale").toInt(&ok);
523 if (ok) setEnergyScale(scale);
524 256
525 size_t windowSize = attributes.value("windowSize").toUInt(&ok); 257 size_t windowSize = attributes.value("windowSize").toUInt(&ok);
526 if (ok) setWindowSize(windowSize); 258 if (ok) setWindowSize(windowSize);
527 259
528 size_t windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok); 260 size_t windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok);
529 if (ok) setWindowHopLevel(windowHopLevel); 261 if (ok) setWindowHopLevel(windowHopLevel);
530
531 float gain = attributes.value("gain").toFloat(&ok);
532 if (ok) setGain(gain);
533
534 bool normalize = (attributes.value("normalize").trimmed() == "true");
535 setNormalize(normalize);
536 } 262 }
537 263
538 bool 264 bool
539 SpectrumLayer::getValueExtents(float &min, float &max, bool &logarithmic, 265 SpectrumLayer::getValueExtents(float &min, float &max, bool &logarithmic,
540 QString &units) const 266 QString &units) const