Mercurial > hg > svgui
comparison layer/SliceLayer.cpp @ 1324:13d9b422f7fe zoom
Merge from default branch
author | Chris Cannam |
---|---|
date | Mon, 17 Sep 2018 13:51:31 +0100 |
parents | 51e6125627fa |
children | d79e21855aef |
comparison
equal
deleted
inserted
replaced
1183:57d192e26331 | 1324:13d9b422f7fe |
---|---|
29 #include <QTextStream> | 29 #include <QTextStream> |
30 | 30 |
31 | 31 |
32 SliceLayer::SliceLayer() : | 32 SliceLayer::SliceLayer() : |
33 m_sliceableModel(0), | 33 m_sliceableModel(0), |
34 m_colourMap(0), | 34 m_colourMap(int(ColourMapper::Ice)), |
35 m_energyScale(dBScale), | 35 m_energyScale(dBScale), |
36 m_samplingMode(SampleMean), | 36 m_samplingMode(SampleMean), |
37 m_plotStyle(PlotSteps), | 37 m_plotStyle(PlotLines), |
38 m_binScale(LinearBins), | 38 m_binScale(LinearBins), |
39 m_normalize(false), | 39 m_normalize(false), |
40 m_threshold(0.0), | 40 m_threshold(0.0), |
41 m_initialThreshold(0.0), | 41 m_initialThreshold(0.0), |
42 m_gain(1.0), | 42 m_gain(1.0), |
43 m_minbin(0), | |
44 m_maxbin(0), | |
43 m_currentf0(0), | 45 m_currentf0(0), |
44 m_currentf1(0) | 46 m_currentf1(0) |
45 { | 47 { |
46 } | 48 } |
47 | 49 |
63 | 65 |
64 if (m_sliceableModel == sliceable) return; | 66 if (m_sliceableModel == sliceable) return; |
65 | 67 |
66 m_sliceableModel = sliceable; | 68 m_sliceableModel = sliceable; |
67 | 69 |
70 if (!m_sliceableModel) return; | |
71 | |
68 connectSignals(m_sliceableModel); | 72 connectSignals(m_sliceableModel); |
69 | 73 |
74 m_minbin = 0; | |
75 m_maxbin = m_sliceableModel->getHeight(); | |
76 | |
70 emit modelReplaced(); | 77 emit modelReplaced(); |
78 emit layerParametersChanged(); | |
71 } | 79 } |
72 | 80 |
73 void | 81 void |
74 SliceLayer::sliceableModelReplaced(const Model *orig, const Model *replacement) | 82 SliceLayer::sliceableModelReplaced(const Model *orig, const Model *replacement) |
75 { | 83 { |
105 { | 113 { |
106 minbin = 0; | 114 minbin = 0; |
107 maxbin = 0; | 115 maxbin = 0; |
108 if (!m_sliceableModel) return ""; | 116 if (!m_sliceableModel) return ""; |
109 | 117 |
110 int xorigin = m_xorigins[v]; | 118 minbin = int(getBinForX(v, p.x())); |
111 int w = v->getPaintWidth() - xorigin - 1; | 119 maxbin = int(getBinForX(v, p.x() + 1)); |
112 | 120 |
113 int mh = m_sliceableModel->getHeight(); | 121 int mh = m_sliceableModel->getHeight(); |
114 minbin = getBinForX(p.x() - xorigin, mh, w); | |
115 maxbin = getBinForX(p.x() - xorigin + 1, mh, w); | |
116 | |
117 if (minbin >= mh) minbin = mh - 1; | 122 if (minbin >= mh) minbin = mh - 1; |
118 if (maxbin >= mh) maxbin = mh - 1; | 123 if (maxbin >= mh) maxbin = mh - 1; |
119 if (minbin < 0) minbin = 0; | 124 if (minbin < 0) minbin = 0; |
120 if (maxbin < 0) maxbin = 0; | 125 if (maxbin < 0) maxbin = 0; |
121 | 126 |
131 | 136 |
132 QString rtrangestr = QString("%1 s").arg((rt1 - rt0).toText().c_str()); | 137 QString rtrangestr = QString("%1 s").arg((rt1 - rt0).toText().c_str()); |
133 | 138 |
134 if (includeBinDescription) { | 139 if (includeBinDescription) { |
135 | 140 |
141 int i0 = minbin - m_minbin; | |
142 int i1 = maxbin - m_minbin; | |
143 | |
136 float minvalue = 0.0; | 144 float minvalue = 0.0; |
137 if (minbin < int(m_values.size())) minvalue = m_values[minbin]; | 145 if (in_range_for(m_values, i0)) minvalue = m_values[i0]; |
138 | 146 |
139 float maxvalue = minvalue; | 147 float maxvalue = minvalue; |
140 if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; | 148 if (in_range_for(m_values, i1)) maxvalue = m_values[i1]; |
141 | 149 |
142 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); | 150 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); |
143 | 151 |
144 QString binstr; | 152 QString binstr; |
145 if (maxbin != minbin) { | 153 if (maxbin != minbin) { |
146 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); | 154 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); |
178 return description; | 186 return description; |
179 } | 187 } |
180 } | 188 } |
181 | 189 |
182 double | 190 double |
183 SliceLayer::getXForBin(int bin, int count, double w) const | 191 SliceLayer::getXForBin(const LayerGeometryProvider *v, double bin) const |
184 { | 192 { |
185 double x = 0; | 193 double x = 0; |
194 | |
195 bin -= m_minbin; | |
196 if (bin < 0) bin = 0; | |
197 | |
198 double count = m_maxbin - m_minbin; | |
199 if (count < 0) count = 0; | |
200 | |
201 int pw = v->getPaintWidth(); | |
202 int origin = m_xorigins[v->getId()]; | |
203 int w = pw - origin; | |
204 if (w < 1) w = 1; | |
186 | 205 |
187 switch (m_binScale) { | 206 switch (m_binScale) { |
188 | 207 |
189 case LinearBins: | 208 case LinearBins: |
190 x = (w * bin) / count; | 209 x = (w * bin) / count; |
191 break; | 210 break; |
192 | 211 |
193 case LogBins: | 212 case LogBins: |
194 x = (w * log10(bin + 1)) / log10(count + 1); | 213 // The 0.8 here is an awkward compromise. Our x-coord is |
214 // proportional to log of bin number, with the x-coord "of a | |
215 // bin" being that of the left edge of the bin range. We can't | |
216 // start counting bins from 0, as that would give us x = -Inf | |
217 // and hide the first bin entirely. But if we start from 1, we | |
218 // are giving a lot of space to the first bin, which in most | |
219 // display modes won't be used because the "point" location | |
220 // for that bin is in the middle of it. Yet in some modes | |
221 // we'll still want it. A compromise is to count our first bin | |
222 // as "a bit less than 1", so that most of it is visible but a | |
223 // bit is tactfully cropped at the left edge so it doesn't | |
224 // take up so much space. | |
225 x = (w * log10(bin + 0.8)) / log10(count + 0.8); | |
195 break; | 226 break; |
196 | 227 |
197 case InvertedLogBins: | 228 case InvertedLogBins: |
198 x = w - (w * log10(count - bin - 1)) / log10(count); | 229 x = w - (w * log10(count - bin - 1)) / log10(count); |
199 break; | 230 break; |
200 } | 231 } |
201 | 232 |
202 return x; | 233 return x + origin; |
203 } | 234 } |
204 | 235 |
205 int | 236 double |
206 SliceLayer::getBinForX(double x, int count, double w) const | 237 SliceLayer::getBinForX(const LayerGeometryProvider *v, double x) const |
207 { | 238 { |
208 int bin = 0; | 239 double bin = 0; |
209 | 240 |
241 double count = m_maxbin - m_minbin; | |
242 if (count < 0) count = 0; | |
243 | |
244 int pw = v->getPaintWidth(); | |
245 int origin = m_xorigins[v->getId()]; | |
246 | |
247 int w = pw - origin; | |
248 if (w < 1) w = 1; | |
249 | |
250 x = x - origin; | |
251 if (x < 0) x = 0; | |
252 | |
253 double eps = 1e-10; | |
254 | |
210 switch (m_binScale) { | 255 switch (m_binScale) { |
211 | 256 |
212 case LinearBins: | 257 case LinearBins: |
213 bin = int((x * count) / w + 0.0001); | 258 bin = (x * count) / w + eps; |
214 break; | 259 break; |
215 | 260 |
216 case LogBins: | 261 case LogBins: |
217 bin = int(pow(10.0, (x * log10(count + 1)) / w) - 1 + 0.0001); | 262 // See comment in getXForBin |
263 bin = pow(10.0, (x * log10(count + 0.8)) / w) - 0.8 + eps; | |
218 break; | 264 break; |
219 | 265 |
220 case InvertedLogBins: | 266 case InvertedLogBins: |
221 bin = count + 1 - int(pow(10.0, (log10(count) * (w - x)) / double(w)) + 0.0001); | 267 bin = count + 1 - pow(10.0, (log10(count) * (w - x)) / double(w)) + eps; |
222 break; | 268 break; |
223 } | 269 } |
224 | 270 |
225 return bin; | 271 return bin + m_minbin; |
226 } | 272 } |
227 | 273 |
228 double | 274 double |
229 SliceLayer::getYForValue(double value, const LayerGeometryProvider *v, double &norm) const | 275 SliceLayer::getYForValue(const LayerGeometryProvider *v, double value, double &norm) const |
230 { | 276 { |
231 norm = 0.0; | 277 norm = 0.0; |
232 | 278 |
233 if (m_yorigins.find(v) == m_yorigins.end()) return 0; | 279 if (m_yorigins.find(v->getId()) == m_yorigins.end()) return 0; |
234 | 280 |
235 value *= m_gain; | 281 value *= m_gain; |
236 | 282 |
237 int yorigin = m_yorigins[v]; | 283 int yorigin = m_yorigins[v->getId()]; |
238 int h = m_heights[v]; | 284 int h = m_heights[v->getId()]; |
239 double thresh = getThresholdDb(); | 285 double thresh = getThresholdDb(); |
240 | 286 |
241 double y = 0.0; | 287 double y = 0.0; |
242 | 288 |
243 if (h <= 0) return y; | 289 if (h <= 0) return y; |
260 y = yorigin - y; | 306 y = yorigin - y; |
261 break; | 307 break; |
262 | 308 |
263 case AbsoluteScale: | 309 case AbsoluteScale: |
264 value = fabs(value); | 310 value = fabs(value); |
265 // and fall through | 311 #if (__GNUC__ >= 7) |
312 __attribute__ ((fallthrough)); | |
313 #endif | |
266 | 314 |
267 case LinearScale: | 315 case LinearScale: |
268 default: | 316 default: |
269 norm = (value - m_threshold); | 317 norm = (value - m_threshold); |
270 if (norm < 0) norm = 0; | 318 if (norm < 0) norm = 0; |
274 | 322 |
275 return y; | 323 return y; |
276 } | 324 } |
277 | 325 |
278 double | 326 double |
279 SliceLayer::getValueForY(double y, const LayerGeometryProvider *v) const | 327 SliceLayer::getValueForY(const LayerGeometryProvider *v, double y) const |
280 { | 328 { |
281 double value = 0.0; | 329 double value = 0.0; |
282 | 330 |
283 if (m_yorigins.find(v) == m_yorigins.end()) return value; | 331 if (m_yorigins.find(v->getId()) == m_yorigins.end()) return value; |
284 | 332 |
285 int yorigin = m_yorigins[v]; | 333 int yorigin = m_yorigins[v->getId()]; |
286 int h = m_heights[v]; | 334 int h = m_heights[v->getId()]; |
287 double thresh = getThresholdDb(); | 335 double thresh = getThresholdDb(); |
288 | 336 |
289 if (h <= 0) return value; | 337 if (h <= 0) return value; |
290 | 338 |
291 y = yorigin - y; | 339 y = yorigin - y; |
323 paint.setBrush(Qt::NoBrush); | 371 paint.setBrush(Qt::NoBrush); |
324 | 372 |
325 if (v->getViewManager() && v->getViewManager()->shouldShowScaleGuides()) { | 373 if (v->getViewManager() && v->getViewManager()->shouldShowScaleGuides()) { |
326 if (!m_scalePoints.empty()) { | 374 if (!m_scalePoints.empty()) { |
327 paint.setPen(QColor(240, 240, 240)); //!!! and dark background? | 375 paint.setPen(QColor(240, 240, 240)); //!!! and dark background? |
376 int ratio = int(round(double(v->getPaintHeight()) / | |
377 m_scalePaintHeight)); | |
328 for (int i = 0; i < (int)m_scalePoints.size(); ++i) { | 378 for (int i = 0; i < (int)m_scalePoints.size(); ++i) { |
329 paint.drawLine(0, m_scalePoints[i], rect.width(), m_scalePoints[i]); | 379 paint.drawLine(0, m_scalePoints[i] * ratio, |
380 rect.width(), m_scalePoints[i] * ratio); | |
330 } | 381 } |
331 } | 382 } |
332 } | 383 } |
333 | 384 |
334 paint.setPen(getBaseQColor()); | 385 if (m_plotStyle == PlotBlocks) { |
386 // Must use actual zero-width pen, too slow otherwise | |
387 paint.setPen(QPen(getBaseQColor(), 0)); | |
388 } else { | |
389 paint.setPen(PaintAssistant::scalePen(getBaseQColor())); | |
390 } | |
335 | 391 |
336 int xorigin = getVerticalScaleWidth(v, true, paint) + 1; | 392 int xorigin = getVerticalScaleWidth(v, true, paint) + 1; |
337 int w = v->getPaintWidth() - xorigin - 1; | 393 m_xorigins[v->getId()] = xorigin; // for use in getFeatureDescription |
338 | |
339 m_xorigins[v] = xorigin; // for use in getFeatureDescription | |
340 | 394 |
341 int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 7; | 395 int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 7; |
342 int h = yorigin - paint.fontMetrics().height() - 8; | 396 int h = yorigin - paint.fontMetrics().height() - 8; |
343 | 397 |
344 m_yorigins[v] = yorigin; // for getYForValue etc | 398 m_yorigins[v->getId()] = yorigin; // for getYForValue etc |
345 m_heights[v] = h; | 399 m_heights[v->getId()] = h; |
346 | 400 |
347 if (h <= 0) return; | 401 if (h <= 0) return; |
348 | 402 |
349 QPainterPath path; | 403 QPainterPath path; |
350 | 404 |
351 int mh = m_sliceableModel->getHeight(); | 405 int mh = m_sliceableModel->getHeight(); |
352 | 406 int bin0 = 0; |
407 | |
408 if (m_maxbin > m_minbin) { | |
409 mh = m_maxbin - m_minbin; | |
410 bin0 = m_minbin; | |
411 } | |
412 | |
353 int divisor = 0; | 413 int divisor = 0; |
354 | 414 |
355 m_values.clear(); | 415 m_values.clear(); |
356 for (int bin = 0; bin < mh; ++bin) { | 416 for (int bin = 0; bin < mh; ++bin) { |
357 m_values.push_back(0.0); | 417 m_values.push_back(0.0); |
381 getBiasCurve(curve); | 441 getBiasCurve(curve); |
382 int cs = int(curve.size()); | 442 int cs = int(curve.size()); |
383 | 443 |
384 for (int col = col0; col <= col1; ++col) { | 444 for (int col = col0; col <= col1; ++col) { |
385 for (int bin = 0; bin < mh; ++bin) { | 445 for (int bin = 0; bin < mh; ++bin) { |
386 float value = m_sliceableModel->getValueAt(col, bin); | 446 float value = m_sliceableModel->getValueAt(col, bin0 + bin); |
387 if (bin < cs) value *= curve[bin]; | 447 if (bin < cs) value *= curve[bin]; |
388 if (m_samplingMode == SamplePeak) { | 448 if (m_samplingMode == SamplePeak) { |
389 if (value > m_values[bin]) m_values[bin] = value; | 449 if (value > m_values[bin]) m_values[bin] = value; |
390 } else { | 450 } else { |
391 m_values[bin] += value; | 451 m_values[bin] += value; |
405 for (int bin = 0; bin < mh; ++bin) { | 465 for (int bin = 0; bin < mh; ++bin) { |
406 m_values[bin] /= max; | 466 m_values[bin] /= max; |
407 } | 467 } |
408 } | 468 } |
409 | 469 |
410 double nx = xorigin; | 470 double nx = getXForBin(v, bin0); |
411 | 471 |
412 ColourMapper mapper(m_colourMap, 0, 1); | 472 ColourMapper mapper(m_colourMap, 0, 1); |
413 | 473 |
414 for (int bin = 0; bin < mh; ++bin) { | 474 for (int bin = 0; bin < mh; ++bin) { |
415 | 475 |
416 double x = nx; | 476 double x = nx; |
417 nx = xorigin + getXForBin(bin + 1, mh, w); | 477 nx = getXForBin(v, bin + bin0 + 1); |
418 | 478 |
419 double value = m_values[bin]; | 479 double value = m_values[bin]; |
420 double norm = 0.0; | 480 double norm = 0.0; |
421 double y = getYForValue(value, v, norm); | 481 double y = getYForValue(v, value, norm); |
422 | 482 |
423 if (m_plotStyle == PlotLines) { | 483 if (m_plotStyle == PlotLines) { |
424 | 484 |
425 if (bin == 0) { | 485 if (bin == 0) { |
426 path.moveTo(x, y); | 486 path.moveTo((x + nx) / 2, y); |
427 } else { | 487 } else { |
428 path.lineTo(x, y); | 488 path.lineTo((x + nx) / 2, y); |
429 } | 489 } |
430 | 490 |
431 } else if (m_plotStyle == PlotSteps) { | 491 } else if (m_plotStyle == PlotSteps) { |
432 | 492 |
433 if (bin == 0) { | 493 if (bin == 0) { |
454 | 514 |
455 if (m_plotStyle != PlotFilledBlocks) { | 515 if (m_plotStyle != PlotFilledBlocks) { |
456 paint.drawPath(path); | 516 paint.drawPath(path); |
457 } | 517 } |
458 paint.restore(); | 518 paint.restore(); |
459 /* | |
460 QPoint discard; | |
461 | |
462 if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount() && | |
463 v->shouldIlluminateLocalFeatures(this, discard)) { | |
464 | |
465 int sampleRate = m_sliceableModel->getSampleRate(); | |
466 | |
467 QString startText = QString("%1 / %2") | |
468 .arg(QString::fromStdString | |
469 (RealTime::frame2RealTime | |
470 (f0, sampleRate).toText(true))) | |
471 .arg(f0); | |
472 | |
473 QString endText = QString(" %1 / %2") | |
474 .arg(QString::fromStdString | |
475 (RealTime::frame2RealTime | |
476 (f1, sampleRate).toText(true))) | |
477 .arg(f1); | |
478 | |
479 QString durationText = QString("(%1 / %2) ") | |
480 .arg(QString::fromStdString | |
481 (RealTime::frame2RealTime | |
482 (f1 - f0 + 1, sampleRate).toText(true))) | |
483 .arg(f1 - f0 + 1); | |
484 | |
485 v->drawVisibleText | |
486 (paint, xorigin + 5, | |
487 paint.fontMetrics().ascent() + 5, | |
488 startText, PaintAssistant::OutlinedText); | |
489 | |
490 v->drawVisibleText | |
491 (paint, xorigin + 5, | |
492 paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10, | |
493 endText, PaintAssistant::OutlinedText); | |
494 | |
495 v->drawVisibleText | |
496 (paint, xorigin + 5, | |
497 paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15, | |
498 durationText, PaintAssistant::OutlinedText); | |
499 } | |
500 */ | |
501 } | 519 } |
502 | 520 |
503 int | 521 int |
504 SliceLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const | 522 SliceLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const |
505 { | 523 { |
524 int width; | |
506 if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) { | 525 if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) { |
507 return std::max(paint.fontMetrics().width("0.0") + 13, | 526 width = std::max(paint.fontMetrics().width("0.0") + 13, |
508 paint.fontMetrics().width("x10-10")); | 527 paint.fontMetrics().width("x10-10")); |
509 } else { | 528 } else { |
510 return std::max(paint.fontMetrics().width(tr("0dB")), | 529 width = std::max(paint.fontMetrics().width(tr("0dB")), |
511 paint.fontMetrics().width(tr("-Inf"))) + 13; | 530 paint.fontMetrics().width(tr("-Inf"))) + 13; |
512 } | 531 } |
532 return width; | |
513 } | 533 } |
514 | 534 |
515 void | 535 void |
516 SliceLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const | 536 SliceLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const |
517 { | 537 { |
535 (paint, actual, thresh, 1.0 / m_gain, | 555 (paint, actual, thresh, 1.0 / m_gain, |
536 PaintAssistant::Scale(m_energyScale), | 556 PaintAssistant::Scale(m_energyScale), |
537 mult, | 557 mult, |
538 const_cast<std::vector<int> *>(&m_scalePoints)); | 558 const_cast<std::vector<int> *>(&m_scalePoints)); |
539 | 559 |
560 // Ugly hack (but then everything about this scale drawing is a | |
561 // bit ugly). In pixel-doubling hi-dpi scenarios, the scale is | |
562 // painted at pixel-doubled resolution but we do explicit | |
563 // pixel-doubling ourselves when painting the layer content. We | |
564 // make a note of this here so that we can compare with the | |
565 // equivalent dimension in the paint method when deciding where to | |
566 // place scale continuation lines. | |
567 m_scalePaintHeight = v->getPaintHeight(); | |
568 | |
540 if (mult != 1 && mult != 0) { | 569 if (mult != 1 && mult != 0) { |
541 int log = int(lrint(log10(mult))); | 570 int log = int(lrint(log10(mult))); |
542 QString a = tr("x10"); | 571 QString a = tr("x10"); |
543 QString b = QString("%1").arg(-log); | 572 QString b = QString("%1").arg(-log); |
544 paint.drawText(3, 8 + paint.fontMetrics().ascent(), a); | 573 paint.drawText(3, 8 + paint.fontMetrics().ascent(), a); |
545 paint.drawText(3 + paint.fontMetrics().width(a), | 574 paint.drawText(3 + paint.fontMetrics().width(a), |
546 3 + paint.fontMetrics().ascent(), b); | 575 3 + paint.fontMetrics().ascent(), b); |
576 } | |
577 } | |
578 | |
579 bool | |
580 SliceLayer::hasLightBackground() const | |
581 { | |
582 if (usesSolidColour()) { | |
583 ColourMapper mapper(m_colourMap, 0, 1); | |
584 return mapper.hasLightBackground(); | |
585 } else { | |
586 return SingleColourLayer::hasLightBackground(); | |
547 } | 587 } |
548 } | 588 } |
549 | 589 |
550 Layer::PropertyList | 590 Layer::PropertyList |
551 SliceLayer::getProperties() const | 591 SliceLayer::getProperties() const |
589 if (name == "Threshold") return RangeProperty; | 629 if (name == "Threshold") return RangeProperty; |
590 if (name == "Plot Type") return ValueProperty; | 630 if (name == "Plot Type") return ValueProperty; |
591 if (name == "Scale") return ValueProperty; | 631 if (name == "Scale") return ValueProperty; |
592 if (name == "Sampling Mode") return ValueProperty; | 632 if (name == "Sampling Mode") return ValueProperty; |
593 if (name == "Bin Scale") return ValueProperty; | 633 if (name == "Bin Scale") return ValueProperty; |
594 if (name == "Colour" && m_plotStyle == PlotFilledBlocks) return ValueProperty; | 634 if (name == "Colour" && usesSolidColour()) return ColourMapProperty; |
595 return SingleColourLayer::getPropertyType(name); | 635 return SingleColourLayer::getPropertyType(name); |
596 } | 636 } |
597 | 637 |
598 QString | 638 QString |
599 SliceLayer::getPropertyGroupName(const PropertyName &name) const | 639 SliceLayer::getPropertyGroupName(const PropertyName &name) const |
619 if (!max) max = &garbage1; | 659 if (!max) max = &garbage1; |
620 if (!deflt) deflt = &garbage2; | 660 if (!deflt) deflt = &garbage2; |
621 | 661 |
622 if (name == "Gain") { | 662 if (name == "Gain") { |
623 | 663 |
624 *min = -50; | 664 *min = -50; |
625 *max = 50; | 665 *max = 50; |
626 *deflt = 0; | 666 *deflt = 0; |
627 | 667 |
628 cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl; | 668 // cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl; |
629 | 669 |
630 val = int(lrint(log10(m_gain) * 20.0)); | 670 val = int(lrint(log10(m_gain) * 20.0)); |
631 if (val < *min) val = *min; | 671 if (val < *min) val = *min; |
632 if (val > *max) val = *max; | 672 if (val > *max) val = *max; |
633 | 673 |
634 } else if (name == "Threshold") { | 674 } else if (name == "Threshold") { |
635 | 675 |
636 *min = -80; | 676 *min = -80; |
637 *max = 0; | 677 *max = 0; |
638 | 678 |
639 *deflt = int(lrint(AudioLevel::multiplier_to_dB(m_initialThreshold))); | 679 *deflt = int(lrint(AudioLevel::multiplier_to_dB(m_initialThreshold))); |
640 if (*deflt < *min) *deflt = *min; | 680 if (*deflt < *min) *deflt = *min; |
641 if (*deflt > *max) *deflt = *max; | 681 if (*deflt > *max) *deflt = *max; |
642 | 682 |
643 val = int(lrint(AudioLevel::multiplier_to_dB(m_threshold))); | 683 val = int(lrint(AudioLevel::multiplier_to_dB(m_threshold))); |
644 if (val < *min) val = *min; | 684 if (val < *min) val = *min; |
645 if (val > *max) val = *max; | 685 if (val > *max) val = *max; |
646 | 686 |
647 } else if (name == "Normalize") { | 687 } else if (name == "Normalize") { |
648 | 688 |
649 val = (m_normalize ? 1 : 0); | 689 val = (m_normalize ? 1 : 0); |
650 *deflt = 0; | 690 *deflt = 0; |
651 | 691 |
652 } else if (name == "Colour" && m_plotStyle == PlotFilledBlocks) { | 692 } else if (name == "Colour" && usesSolidColour()) { |
653 | 693 |
654 *min = 0; | 694 *min = 0; |
655 *max = ColourMapper::getColourMapCount() - 1; | 695 *max = ColourMapper::getColourMapCount() - 1; |
656 *deflt = 0; | 696 *deflt = int(ColourMapper::Ice); |
657 | 697 |
658 val = m_colourMap; | 698 val = m_colourMap; |
659 | 699 |
660 } else if (name == "Scale") { | 700 } else if (name == "Scale") { |
661 | 701 |
662 *min = 0; | 702 *min = 0; |
663 *max = 3; | 703 *max = 3; |
664 *deflt = (int)dBScale; | 704 *deflt = (int)dBScale; |
665 | 705 |
666 val = (int)m_energyScale; | 706 val = (int)m_energyScale; |
667 | 707 |
668 } else if (name == "Sampling Mode") { | 708 } else if (name == "Sampling Mode") { |
669 | 709 |
670 *min = 0; | 710 *min = 0; |
671 *max = 2; | 711 *max = 2; |
672 *deflt = (int)SampleMean; | 712 *deflt = (int)SampleMean; |
673 | 713 |
674 val = (int)m_samplingMode; | 714 val = (int)m_samplingMode; |
675 | 715 |
676 } else if (name == "Plot Type") { | 716 } else if (name == "Plot Type") { |
677 | 717 |
678 *min = 0; | 718 *min = 0; |
679 *max = 3; | 719 *max = 3; |
689 // *max = 1; // I don't think we really do want to offer inverted log | 729 // *max = 1; // I don't think we really do want to offer inverted log |
690 | 730 |
691 val = (int)m_binScale; | 731 val = (int)m_binScale; |
692 | 732 |
693 } else { | 733 } else { |
694 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt); | 734 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt); |
695 } | 735 } |
696 | 736 |
697 return val; | 737 return val; |
698 } | 738 } |
699 | 739 |
700 QString | 740 QString |
701 SliceLayer::getPropertyValueLabel(const PropertyName &name, | 741 SliceLayer::getPropertyValueLabel(const PropertyName &name, |
702 int value) const | 742 int value) const |
703 { | 743 { |
704 if (name == "Colour" && m_plotStyle == PlotFilledBlocks) { | 744 if (name == "Colour" && usesSolidColour()) { |
705 return ColourMapper::getColourMapName(value); | 745 return ColourMapper::getColourMapName(value); |
706 } | 746 } |
707 if (name == "Scale") { | 747 if (name == "Scale") { |
708 switch (value) { | 748 switch (value) { |
709 default: | 749 default: |
710 case 0: return tr("Linear"); | 750 case 0: return tr("Linear"); |
711 case 1: return tr("Meter"); | 751 case 1: return tr("Meter"); |
712 case 2: return tr("Log"); | 752 case 2: return tr("Log"); |
713 case 3: return tr("Absolute"); | 753 case 3: return tr("Absolute"); |
714 } | 754 } |
715 } | 755 } |
716 if (name == "Sampling Mode") { | 756 if (name == "Sampling Mode") { |
717 switch (value) { | 757 switch (value) { |
718 default: | 758 default: |
719 case 0: return tr("Any"); | 759 case 0: return tr("Any"); |
720 case 1: return tr("Mean"); | 760 case 1: return tr("Mean"); |
721 case 2: return tr("Peak"); | 761 case 2: return tr("Peak"); |
722 } | 762 } |
723 } | 763 } |
724 if (name == "Plot Type") { | 764 if (name == "Plot Type") { |
725 switch (value) { | 765 switch (value) { |
726 default: | 766 default: |
727 case 0: return tr("Lines"); | 767 case 0: return tr("Lines"); |
728 case 1: return tr("Steps"); | 768 case 1: return tr("Steps"); |
729 case 2: return tr("Blocks"); | 769 case 2: return tr("Blocks"); |
730 case 3: return tr("Colours"); | 770 case 3: return tr("Colours"); |
731 } | 771 } |
732 } | 772 } |
733 if (name == "Bin Scale") { | 773 if (name == "Bin Scale") { |
734 switch (value) { | 774 switch (value) { |
735 default: | 775 default: |
736 case 0: return tr("Linear"); | 776 case 0: return tr("Linear"); |
737 case 1: return tr("Log"); | 777 case 1: return tr("Log"); |
738 case 2: return tr("Rev Log"); | 778 case 2: return tr("Rev Log"); |
739 } | 779 } |
740 } | 780 } |
741 return SingleColourLayer::getPropertyValueLabel(name, value); | 781 return SingleColourLayer::getPropertyValueLabel(name, value); |
742 } | 782 } |
743 | 783 |
744 RangeMapper * | 784 RangeMapper * |
755 | 795 |
756 void | 796 void |
757 SliceLayer::setProperty(const PropertyName &name, int value) | 797 SliceLayer::setProperty(const PropertyName &name, int value) |
758 { | 798 { |
759 if (name == "Gain") { | 799 if (name == "Gain") { |
760 setGain(powf(10, float(value)/20.0f)); | 800 setGain(powf(10, float(value)/20.0f)); |
761 } else if (name == "Threshold") { | 801 } else if (name == "Threshold") { |
762 if (value == -80) setThreshold(0.0f); | 802 if (value == -80) setThreshold(0.0f); |
763 else setThreshold(float(AudioLevel::dB_to_multiplier(value))); | 803 else setThreshold(float(AudioLevel::dB_to_multiplier(value))); |
764 } else if (name == "Colour" && m_plotStyle == PlotFilledBlocks) { | 804 } else if (name == "Colour" && usesSolidColour()) { |
765 setFillColourMap(value); | 805 setFillColourMap(value); |
766 } else if (name == "Scale") { | 806 } else if (name == "Scale") { |
767 switch (value) { | 807 switch (value) { |
768 default: | 808 default: |
769 case 0: setEnergyScale(LinearScale); break; | 809 case 0: setEnergyScale(LinearScale); break; |
770 case 1: setEnergyScale(MeterScale); break; | 810 case 1: setEnergyScale(MeterScale); break; |
771 case 2: setEnergyScale(dBScale); break; | 811 case 2: setEnergyScale(dBScale); break; |
772 case 3: setEnergyScale(AbsoluteScale); break; | 812 case 3: setEnergyScale(AbsoluteScale); break; |
773 } | 813 } |
774 } else if (name == "Plot Type") { | 814 } else if (name == "Plot Type") { |
775 setPlotStyle(PlotStyle(value)); | 815 setPlotStyle(PlotStyle(value)); |
776 } else if (name == "Sampling Mode") { | 816 } else if (name == "Sampling Mode") { |
777 switch (value) { | 817 switch (value) { |
778 default: | 818 default: |
779 case 0: setSamplingMode(NearestSample); break; | 819 case 0: setSamplingMode(NearestSample); break; |
780 case 1: setSamplingMode(SampleMean); break; | 820 case 1: setSamplingMode(SampleMean); break; |
781 case 2: setSamplingMode(SamplePeak); break; | 821 case 2: setSamplingMode(SamplePeak); break; |
782 } | 822 } |
783 } else if (name == "Bin Scale") { | 823 } else if (name == "Bin Scale") { |
784 switch (value) { | 824 switch (value) { |
785 default: | 825 default: |
786 case 0: setBinScale(LinearBins); break; | 826 case 0: setBinScale(LinearBins); break; |
787 case 1: setBinScale(LogBins); break; | 827 case 1: setBinScale(LogBins); break; |
788 case 2: setBinScale(InvertedLogBins); break; | 828 case 2: setBinScale(InvertedLogBins); break; |
789 } | 829 } |
790 } else if (name == "Normalize") { | 830 } else if (name == "Normalize") { |
791 setNormalize(value ? true : false); | 831 setNormalize(value ? true : false); |
792 } else { | 832 } else { |
793 SingleColourLayer::setProperty(name, value); | 833 SingleColourLayer::setProperty(name, value); |
794 } | 834 } |
795 } | 835 } |
796 | 836 |
884 QString indent, QString extraAttributes) const | 924 QString indent, QString extraAttributes) const |
885 { | 925 { |
886 QString s; | 926 QString s; |
887 | 927 |
888 s += QString("colourScheme=\"%1\" " | 928 s += QString("colourScheme=\"%1\" " |
889 "energyScale=\"%2\" " | 929 "energyScale=\"%2\" " |
890 "samplingMode=\"%3\" " | 930 "samplingMode=\"%3\" " |
891 "plotStyle=\"%4\" " | 931 "plotStyle=\"%4\" " |
892 "binScale=\"%5\" " | 932 "binScale=\"%5\" " |
893 "gain=\"%6\" " | 933 "gain=\"%6\" " |
894 "threshold=\"%7\" " | 934 "threshold=\"%7\" " |
895 "normalize=\"%8\"") | 935 "normalize=\"%8\" %9") |
896 .arg(m_colourMap) | 936 .arg(m_colourMap) |
897 .arg(m_energyScale) | 937 .arg(m_energyScale) |
898 .arg(m_samplingMode) | 938 .arg(m_samplingMode) |
899 .arg(m_plotStyle) | 939 .arg(m_plotStyle) |
900 .arg(m_binScale) | 940 .arg(m_binScale) |
901 .arg(m_gain) | 941 .arg(m_gain) |
902 .arg(m_threshold) | 942 .arg(m_threshold) |
903 .arg(m_normalize ? "true" : "false"); | 943 .arg(m_normalize ? "true" : "false") |
944 .arg(QString("minbin=\"%1\" " | |
945 "maxbin=\"%2\"") | |
946 .arg(m_minbin) | |
947 .arg(m_maxbin)); | |
904 | 948 |
905 SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s); | 949 SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s); |
906 } | 950 } |
907 | 951 |
908 void | 952 void |
911 bool ok = false; | 955 bool ok = false; |
912 | 956 |
913 SingleColourLayer::setProperties(attributes); | 957 SingleColourLayer::setProperties(attributes); |
914 | 958 |
915 EnergyScale scale = (EnergyScale) | 959 EnergyScale scale = (EnergyScale) |
916 attributes.value("energyScale").toInt(&ok); | 960 attributes.value("energyScale").toInt(&ok); |
917 if (ok) setEnergyScale(scale); | 961 if (ok) setEnergyScale(scale); |
918 | 962 |
919 SamplingMode mode = (SamplingMode) | 963 SamplingMode mode = (SamplingMode) |
920 attributes.value("samplingMode").toInt(&ok); | 964 attributes.value("samplingMode").toInt(&ok); |
921 if (ok) setSamplingMode(mode); | 965 if (ok) setSamplingMode(mode); |
922 | 966 |
923 int colourMap = attributes.value("colourScheme").toInt(&ok); | 967 int colourMap = attributes.value("colourScheme").toInt(&ok); |
924 if (ok) setFillColourMap(colourMap); | 968 if (ok) setFillColourMap(colourMap); |
925 | 969 |
926 PlotStyle s = (PlotStyle) | 970 PlotStyle s = (PlotStyle) |
927 attributes.value("plotStyle").toInt(&ok); | 971 attributes.value("plotStyle").toInt(&ok); |
928 if (ok) setPlotStyle(s); | 972 if (ok) setPlotStyle(s); |
929 | 973 |
930 BinScale b = (BinScale) | 974 BinScale b = (BinScale) |
931 attributes.value("binScale").toInt(&ok); | 975 attributes.value("binScale").toInt(&ok); |
932 if (ok) setBinScale(b); | 976 if (ok) setBinScale(b); |
933 | 977 |
934 float gain = attributes.value("gain").toFloat(&ok); | 978 float gain = attributes.value("gain").toFloat(&ok); |
935 if (ok) setGain(gain); | 979 if (ok) setGain(gain); |
936 | 980 |
937 float threshold = attributes.value("threshold").toFloat(&ok); | 981 float threshold = attributes.value("threshold").toFloat(&ok); |
938 if (ok) setThreshold(threshold); | 982 if (ok) setThreshold(threshold); |
939 | 983 |
940 bool normalize = (attributes.value("normalize").trimmed() == "true"); | 984 bool normalize = (attributes.value("normalize").trimmed() == "true"); |
941 setNormalize(normalize); | 985 setNormalize(normalize); |
986 | |
987 bool alsoOk = false; | |
988 | |
989 float min = attributes.value("minbin").toFloat(&ok); | |
990 float max = attributes.value("maxbin").toFloat(&alsoOk); | |
991 if (ok && alsoOk) setDisplayExtents(min, max); | |
942 } | 992 } |
943 | 993 |
944 bool | 994 bool |
945 SliceLayer::getValueExtents(double &, double &, bool &, QString &) const | 995 SliceLayer::getValueExtents(double &min, double &max, bool &logarithmic, |
946 { | 996 QString &unit) const |
947 return false; | 997 { |
948 } | 998 if (!m_sliceableModel) return false; |
949 | 999 |
1000 min = 0; | |
1001 max = double(m_sliceableModel->getHeight()); | |
1002 | |
1003 logarithmic = (m_binScale == BinScale::LogBins); | |
1004 unit = ""; | |
1005 | |
1006 return true; | |
1007 } | |
1008 | |
1009 bool | |
1010 SliceLayer::getDisplayExtents(double &min, double &max) const | |
1011 { | |
1012 if (!m_sliceableModel) return false; | |
1013 | |
1014 double hmax = double(m_sliceableModel->getHeight()); | |
1015 | |
1016 min = m_minbin; | |
1017 max = m_maxbin; | |
1018 if (max <= min) { | |
1019 min = 0; | |
1020 max = hmax; | |
1021 } | |
1022 if (min < 0) min = 0; | |
1023 if (max > hmax) max = hmax; | |
1024 | |
1025 return true; | |
1026 } | |
1027 | |
1028 bool | |
1029 SliceLayer::setDisplayExtents(double min, double max) | |
1030 { | |
1031 if (!m_sliceableModel) return false; | |
1032 | |
1033 m_minbin = int(lrint(min)); | |
1034 m_maxbin = int(lrint(max)); | |
1035 | |
1036 emit layerParametersChanged(); | |
1037 return true; | |
1038 } | |
1039 | |
1040 int | |
1041 SliceLayer::getVerticalZoomSteps(int &defaultStep) const | |
1042 { | |
1043 if (!m_sliceableModel) return 0; | |
1044 | |
1045 defaultStep = 0; | |
1046 int h = m_sliceableModel->getHeight(); | |
1047 return h; | |
1048 } | |
1049 | |
1050 int | |
1051 SliceLayer::getCurrentVerticalZoomStep() const | |
1052 { | |
1053 if (!m_sliceableModel) return 0; | |
1054 | |
1055 double min, max; | |
1056 getDisplayExtents(min, max); | |
1057 return m_sliceableModel->getHeight() - int(lrint(max - min)); | |
1058 } | |
1059 | |
1060 void | |
1061 SliceLayer::setVerticalZoomStep(int step) | |
1062 { | |
1063 if (!m_sliceableModel) return; | |
1064 | |
1065 // SVDEBUG << "SliceLayer::setVerticalZoomStep(" <<step <<"): before: minbin = " << m_minbin << ", maxbin = " << m_maxbin << endl; | |
1066 | |
1067 int dist = m_sliceableModel->getHeight() - step; | |
1068 if (dist < 1) dist = 1; | |
1069 double centre = m_minbin + (m_maxbin - m_minbin) / 2.0; | |
1070 m_minbin = int(lrint(centre - dist/2.0)); | |
1071 if (m_minbin < 0) m_minbin = 0; | |
1072 m_maxbin = m_minbin + dist; | |
1073 if (m_maxbin > m_sliceableModel->getHeight()) m_maxbin = m_sliceableModel->getHeight(); | |
1074 | |
1075 // SVDEBUG << "SliceLayer::setVerticalZoomStep(" <<step <<"): after: minbin = " << m_minbin << ", maxbin = " << m_maxbin << endl; | |
1076 | |
1077 emit layerParametersChanged(); | |
1078 } | |
1079 | |
1080 RangeMapper * | |
1081 SliceLayer::getNewVerticalZoomRangeMapper() const | |
1082 { | |
1083 if (!m_sliceableModel) return 0; | |
1084 | |
1085 return new LinearRangeMapper(0, m_sliceableModel->getHeight(), | |
1086 0, m_sliceableModel->getHeight(), ""); | |
1087 } |