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 }