comparison layer/SpectrumLayer.cpp @ 1216:dc2af6616c83

Merge from branch 3.0-integration
author Chris Cannam
date Fri, 13 Jan 2017 10:29:50 +0000
parents 1badacff7ab2
children ff97318e993c
comparison
equal deleted inserted replaced
1048:e8102ff5573b 1216:dc2af6616c83
19 #include "view/View.h" 19 #include "view/View.h"
20 #include "base/AudioLevel.h" 20 #include "base/AudioLevel.h"
21 #include "base/Preferences.h" 21 #include "base/Preferences.h"
22 #include "base/RangeMapper.h" 22 #include "base/RangeMapper.h"
23 #include "base/Pitch.h" 23 #include "base/Pitch.h"
24 #include "base/Strings.h"
25
24 #include "ColourMapper.h" 26 #include "ColourMapper.h"
27 #include "PaintAssistant.h"
25 28
26 #include <QPainter> 29 #include <QPainter>
27 #include <QTextStream> 30 #include <QTextStream>
28 31
29 32
110 FFTModel *newFFT = new FFTModel(m_originModel, 113 FFTModel *newFFT = new FFTModel(m_originModel,
111 m_channel, 114 m_channel,
112 m_windowType, 115 m_windowType,
113 m_windowSize, 116 m_windowSize,
114 getWindowIncrement(), 117 getWindowIncrement(),
115 m_windowSize, 118 m_windowSize);
116 false,
117 StorageAdviser::Criteria
118 (StorageAdviser::SpeedCritical |
119 StorageAdviser::FrequentLookupLikely));
120 119
121 setSliceableModel(newFFT); 120 setSliceableModel(newFFT);
122 121
123 m_biasCurve.clear(); 122 m_biasCurve.clear();
124 for (int i = 0; i < m_windowSize; ++i) { 123 for (int i = 0; i < m_windowSize; ++i) {
125 m_biasCurve.push_back(1.f / (float(m_windowSize)/2.f)); 124 m_biasCurve.push_back(1.f / (float(m_windowSize)/2.f));
126 } 125 }
127
128 newFFT->resume();
129 126
130 m_newFFTNeeded = false; 127 m_newFFTNeeded = false;
131 } 128 }
132 129
133 Layer::PropertyList 130 Layer::PropertyList
384 381
385 return x; 382 return x;
386 } 383 }
387 384
388 bool 385 bool
389 SpectrumLayer::getXScaleValue(const View *v, int x, 386 SpectrumLayer::getXScaleValue(const LayerGeometryProvider *v, int x,
390 double &value, QString &unit) const 387 double &value, QString &unit) const
391 { 388 {
392 if (m_xorigins.find(v) == m_xorigins.end()) return false; 389 if (m_xorigins.find(v) == m_xorigins.end()) return false;
393 int xorigin = m_xorigins.find(v)->second; 390 int xorigin = m_xorigins.find(v)->second;
394 value = getFrequencyForX(x - xorigin, v->width() - xorigin - 1); 391 value = getFrequencyForX(x - xorigin, v->getPaintWidth() - xorigin - 1);
395 unit = "Hz"; 392 unit = "Hz";
396 return true; 393 return true;
397 } 394 }
398 395
399 bool 396 bool
400 SpectrumLayer::getYScaleValue(const View *v, int y, 397 SpectrumLayer::getYScaleValue(const LayerGeometryProvider *v, int y,
401 double &value, QString &unit) const 398 double &value, QString &unit) const
402 { 399 {
403 value = getValueForY(y, v); 400 value = getValueForY(y, v);
404 401
405 if (m_energyScale == dBScale || m_energyScale == MeterScale) { 402 if (m_energyScale == dBScale || m_energyScale == MeterScale) {
417 414
418 return true; 415 return true;
419 } 416 }
420 417
421 bool 418 bool
422 SpectrumLayer::getYScaleDifference(const View *v, int y0, int y1, 419 SpectrumLayer::getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1,
423 double &diff, QString &unit) const 420 double &diff, QString &unit) const
424 { 421 {
425 bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit); 422 bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit);
426 if (rv && (unit == "dBV")) unit = "dB"; 423 if (rv && (unit == "dBV")) unit = "dB";
427 return rv; 424 return rv;
428 } 425 }
429 426
430 427
431 bool 428 bool
432 SpectrumLayer::getCrosshairExtents(View *v, QPainter &paint, 429 SpectrumLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint,
433 QPoint cursorPos, 430 QPoint cursorPos,
434 std::vector<QRect> &extents) const 431 std::vector<QRect> &extents) const
435 { 432 {
436 QRect vertical(cursorPos.x(), cursorPos.y(), 1, v->height() - cursorPos.y()); 433 QRect vertical(cursorPos.x(), cursorPos.y(), 1, v->getPaintHeight() - cursorPos.y());
437 extents.push_back(vertical); 434 extents.push_back(vertical);
438 435
439 QRect horizontal(0, cursorPos.y(), v->width(), 12); 436 QRect horizontal(0, cursorPos.y(), v->getPaintWidth(), 12);
440 extents.push_back(horizontal); 437 extents.push_back(horizontal);
441 438
442 int hoffset = 2; 439 int hoffset = 2;
443 if (m_binScale == LogBins) hoffset = 13; 440 if (m_binScale == LogBins) hoffset = 13;
444 441
453 paint.fontMetrics().width("-80.000 dBV") + 2, 450 paint.fontMetrics().width("-80.000 dBV") + 2,
454 paint.fontMetrics().height()); 451 paint.fontMetrics().height());
455 extents.push_back(log); 452 extents.push_back(log);
456 453
457 QRect freq(cursorPos.x(), 454 QRect freq(cursorPos.x(),
458 v->height() - paint.fontMetrics().height() - hoffset, 455 v->getPaintHeight() - paint.fontMetrics().height() - hoffset,
459 paint.fontMetrics().width("123456 Hz") + 2, 456 paint.fontMetrics().width("123456 Hz") + 2,
460 paint.fontMetrics().height()); 457 paint.fontMetrics().height());
461 extents.push_back(freq); 458 extents.push_back(freq);
462 459
463 int w(paint.fontMetrics().width("C#10+50c") + 2); 460 int w(paint.fontMetrics().width("C#10+50c") + 2);
464 QRect pitch(cursorPos.x() - w, 461 QRect pitch(cursorPos.x() - w,
465 v->height() - paint.fontMetrics().height() - hoffset, 462 v->getPaintHeight() - paint.fontMetrics().height() - hoffset,
466 w, 463 w,
467 paint.fontMetrics().height()); 464 paint.fontMetrics().height());
468 extents.push_back(pitch); 465 extents.push_back(pitch);
469 466
470 return true; 467 return true;
471 } 468 }
472 469
473 void 470 void
474 SpectrumLayer::paintCrosshairs(View *v, QPainter &paint, 471 SpectrumLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint,
475 QPoint cursorPos) const 472 QPoint cursorPos) const
476 { 473 {
477 if (!m_sliceableModel) return; 474 if (!m_sliceableModel) return;
478 475
479 paint.save(); 476 paint.save();
485 482
486 ColourMapper mapper(m_colourMap, 0, 1); 483 ColourMapper mapper(m_colourMap, 0, 1);
487 paint.setPen(mapper.getContrastingColour()); 484 paint.setPen(mapper.getContrastingColour());
488 485
489 int xorigin = m_xorigins[v]; 486 int xorigin = m_xorigins[v];
490 int w = v->width() - xorigin - 1; 487 int w = v->getPaintWidth() - xorigin - 1;
491 488
492 paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y()); 489 paint.drawLine(xorigin, cursorPos.y(), v->getPaintWidth(), cursorPos.y());
493 paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height()); 490 paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->getPaintHeight());
494 491
495 double fundamental = getFrequencyForX(cursorPos.x() - xorigin, w); 492 double fundamental = getFrequencyForX(cursorPos.x() - xorigin, w);
496 493
497 int hoffset = 2; 494 int hoffset = 2;
498 if (m_binScale == LogBins) hoffset = 13; 495 if (m_binScale == LogBins) hoffset = 13;
499 496
500 v->drawVisibleText(paint, 497 PaintAssistant::drawVisibleText(v, paint,
501 cursorPos.x() + 2, 498 cursorPos.x() + 2,
502 v->height() - 2 - hoffset, 499 v->getPaintHeight() - 2 - hoffset,
503 QString("%1 Hz").arg(fundamental), 500 QString("%1 Hz").arg(fundamental),
504 View::OutlinedText); 501 PaintAssistant::OutlinedText);
505 502
506 if (Pitch::isFrequencyInMidiRange(fundamental)) { 503 if (Pitch::isFrequencyInMidiRange(fundamental)) {
507 QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental); 504 QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental);
508 v->drawVisibleText(paint, 505 PaintAssistant::drawVisibleText(v, paint,
509 cursorPos.x() - paint.fontMetrics().width(pitchLabel) - 2, 506 cursorPos.x() - paint.fontMetrics().width(pitchLabel) - 2,
510 v->height() - 2 - hoffset, 507 v->getPaintHeight() - 2 - hoffset,
511 pitchLabel, 508 pitchLabel,
512 View::OutlinedText); 509 PaintAssistant::OutlinedText);
513 } 510 }
514 511
515 double value = getValueForY(cursorPos.y(), v); 512 double value = getValueForY(cursorPos.y(), v);
516 double thresh = m_threshold; 513 double thresh = m_threshold;
517 double db = thresh; 514 double db = thresh;
518 if (value > 0.0) db = 10.0 * log10(value); 515 if (value > 0.0) db = 10.0 * log10(value);
519 if (db < thresh) db = thresh; 516 if (db < thresh) db = thresh;
520 517
521 v->drawVisibleText(paint, 518 PaintAssistant::drawVisibleText(v, paint,
522 xorigin + 2, 519 xorigin + 2,
523 cursorPos.y() - 2, 520 cursorPos.y() - 2,
524 QString("%1 V").arg(value), 521 QString("%1 V").arg(value),
525 View::OutlinedText); 522 PaintAssistant::OutlinedText);
526 523
527 v->drawVisibleText(paint, 524 PaintAssistant::drawVisibleText(v, paint,
528 xorigin + 2, 525 xorigin + 2,
529 cursorPos.y() + 2 + paint.fontMetrics().ascent(), 526 cursorPos.y() + 2 + paint.fontMetrics().ascent(),
530 QString("%1 dBV").arg(db), 527 QString("%1 dBV").arg(db),
531 View::OutlinedText); 528 PaintAssistant::OutlinedText);
532 529
533 int harmonic = 2; 530 int harmonic = 2;
534 531
535 while (harmonic < 100) { 532 while (harmonic < 100) {
536 533
537 int hx = int(lrint(getXForFrequency(fundamental * harmonic, w))); 534 int hx = int(lrint(getXForFrequency(fundamental * harmonic, w)));
538 hx += xorigin; 535 hx += xorigin;
539 536
540 if (hx < xorigin || hx > v->width()) break; 537 if (hx < xorigin || hx > v->getPaintWidth()) break;
541 538
542 int len = 7; 539 int len = 7;
543 540
544 if (harmonic % 2 == 0) { 541 if (harmonic % 2 == 0) {
545 if (harmonic % 4 == 0) { 542 if (harmonic % 4 == 0) {
559 556
560 paint.restore(); 557 paint.restore();
561 } 558 }
562 559
563 QString 560 QString
564 SpectrumLayer::getFeatureDescription(View *v, QPoint &p) const 561 SpectrumLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &p) const
565 { 562 {
566 if (!m_sliceableModel) return ""; 563 if (!m_sliceableModel) return "";
567 564
568 int minbin = 0, maxbin = 0, range = 0; 565 int minbin = 0, maxbin = 0, range = 0;
569 QString genericDesc = SliceLayer::getFeatureDescriptionAux 566 QString genericDesc = SliceLayer::getFeatureDescriptionAux
609 double mindb = AudioLevel::multiplier_to_dB(minvalue); 606 double mindb = AudioLevel::multiplier_to_dB(minvalue);
610 double maxdb = AudioLevel::multiplier_to_dB(maxvalue); 607 double maxdb = AudioLevel::multiplier_to_dB(maxvalue);
611 QString mindbstr; 608 QString mindbstr;
612 QString maxdbstr; 609 QString maxdbstr;
613 if (mindb == AudioLevel::DB_FLOOR) { 610 if (mindb == AudioLevel::DB_FLOOR) {
614 mindbstr = tr("-Inf"); 611 mindbstr = Strings::minus_infinity;
615 } else { 612 } else {
616 mindbstr = QString("%1").arg(lrint(mindb)); 613 mindbstr = QString("%1").arg(lrint(mindb));
617 } 614 }
618 if (maxdb == AudioLevel::DB_FLOOR) { 615 if (maxdb == AudioLevel::DB_FLOOR) {
619 maxdbstr = tr("-Inf"); 616 maxdbstr = Strings::minus_infinity;
620 } else { 617 } else {
621 maxdbstr = QString("%1").arg(lrint(maxdb)); 618 maxdbstr = QString("%1").arg(lrint(maxdb));
622 } 619 }
623 if (lrint(mindb) != lrint(maxdb)) { 620 if (lrint(mindb) != lrint(maxdb)) {
624 dbstr = tr("%1 - %2").arg(mindbstr).arg(maxdbstr); 621 dbstr = tr("%1 - %2").arg(mindbstr).arg(maxdbstr);
648 645
649 return description; 646 return description;
650 } 647 }
651 648
652 void 649 void
653 SpectrumLayer::paint(View *v, QPainter &paint, QRect rect) const 650 SpectrumLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
654 { 651 {
655 if (!m_originModel || !m_originModel->isOK() || 652 if (!m_originModel || !m_originModel->isOK() ||
656 !m_originModel->isReady()) { 653 !m_originModel->isReady()) {
657 SVDEBUG << "SpectrumLayer::paint: no origin model, or origin model not OK or not ready" << endl; 654 SVDEBUG << "SpectrumLayer::paint: no origin model, or origin model not OK or not ready" << endl;
658 return; 655 return;
667 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); 664 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
668 665
669 double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj 666 double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj
670 667
671 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; 668 int xorigin = getVerticalScaleWidth(v, false, paint) + 1;
672 int w = v->width() - xorigin - 1; 669 int w = v->getPaintWidth() - xorigin - 1;
673 670
674 int pkh = 0; 671 int pkh = 0;
675 //!!! if (m_binScale == LogBins) { 672 //!!! if (m_binScale == LogBins) {
676 pkh = 10; 673 pkh = 10;
677 //!!! } 674 //!!! }
727 724
728 double norm = 0.f; 725 double norm = 0.f;
729 (void)getYForValue(values[bin], v, norm); // don't need return value, need norm 726 (void)getYForValue(values[bin], v, norm); // don't need return value, need norm
730 727
731 paint.setPen(mapper.map(norm)); 728 paint.setPen(mapper.map(norm));
732 paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1); 729 paint.drawLine(xorigin + x, 0, xorigin + x, v->getPaintHeight() - pkh - 1);
733 } 730 }
734 731
735 paint.restore(); 732 paint.restore();
736 } 733 }
737 734
747 //proposition. 744 //proposition.
748 745
749 // if (m_binScale == LogBins) { 746 // if (m_binScale == LogBins) {
750 747
751 // int pkh = 10; 748 // int pkh = 10;
752 int h = v->height(); 749 int h = v->getPaintHeight();
753 750
754 // piano keyboard 751 // piano keyboard
755 //!!! should be in a new paintHorizontalScale()? 752 //!!! should be in a new paintHorizontalScale()?
756 // nice to have a piano keyboard class, of course 753 // nice to have a piano keyboard class, of course
757 754