comparison layer/SpectrumLayer.cpp @ 153:aaa3a53dbb10

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