comparison layer/SpectrumLayer.cpp @ 278:a078aa2932cc

* Fix piano keyboard in spectrum, add pitch labels to frequency displays in measurement rect (clunkily done) and harmonic cursor in spectrum
author Chris Cannam
date Tue, 03 Jul 2007 18:47:39 +0000
parents 8acd30ed735c
children 3c402c6052f6
comparison
equal deleted inserted replaced
277:8acd30ed735c 278:a078aa2932cc
399 extents.push_back(vertical); 399 extents.push_back(vertical);
400 400
401 QRect horizontal(0, cursorPos.y(), v->width(), 12); 401 QRect horizontal(0, cursorPos.y(), v->width(), 12);
402 extents.push_back(horizontal); 402 extents.push_back(horizontal);
403 403
404 QRect label(cursorPos.x(), v->height() - paint.fontMetrics().height(), 404 int hoffset = 1;
405 if (m_binScale == LogBins) hoffset = 12;
406
407 QRect label(cursorPos.x(),
408 v->height() - paint.fontMetrics().height() - hoffset,
405 paint.fontMetrics().width("123456 Hz") + 2, 409 paint.fontMetrics().width("123456 Hz") + 2,
406 paint.fontMetrics().height()); 410 paint.fontMetrics().height());
407 extents.push_back(label); 411 extents.push_back(label);
408 412
413 int w(paint.fontMetrics().width("C#10+50c") + 2);
414 QRect pitch(cursorPos.x() - w,
415 v->height() - paint.fontMetrics().height() - hoffset,
416 w,
417 paint.fontMetrics().height());
418 extents.push_back(pitch);
419
409 return true; 420 return true;
410 } 421 }
411 422
412 void 423 void
413 SpectrumLayer::paintCrosshairs(View *v, QPainter &paint, 424 SpectrumLayer::paintCrosshairs(View *v, QPainter &paint,
424 paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y()); 435 paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y());
425 paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height()); 436 paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height());
426 437
427 float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w); 438 float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w);
428 439
429 paint.drawText(cursorPos.x() + 2, v->height() - 2, 440 int hoffset = 1;
430 QString("%1 Hz").arg(fundamental)); 441 if (m_binScale == LogBins) hoffset = 12;
442
443 v->drawVisibleText(paint,
444 cursorPos.x() + 2,
445 v->height() - 2 - hoffset,
446 QString("%1 Hz").arg(fundamental),
447 View::OutlinedText);
448
449 if (Pitch::isFrequencyInMidiRange(fundamental)) {
450 QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental);
451 v->drawVisibleText(paint,
452 cursorPos.x() - paint.fontMetrics().width(pitchLabel) - 2,
453 v->height() - 2 - hoffset,
454 pitchLabel,
455 View::OutlinedText);
456 }
431 457
432 int harmonic = 2; 458 int harmonic = 2;
433 459
434 while (harmonic < 100) { 460 while (harmonic < 100) {
435 461
564 590
565 float thresh = powf(10, -8) / m_gain; // -80dB 591 float thresh = powf(10, -8) / m_gain; // -80dB
566 592
567 int xorigin = getVerticalScaleWidth(v, paint) + 1; 593 int xorigin = getVerticalScaleWidth(v, paint) + 1;
568 int w = v->width() - xorigin - 1; 594 int w = v->width() - xorigin - 1;
595
596 int pkh = 0;
597 if (m_binScale == LogBins) pkh = 10;
569 598
570 if (fft) { 599 if (fft) {
571 600
572 // draw peak lines 601 // draw peak lines
573 //!!! should be optional 602 //!!! should be optional
599 if (bin < cs) value *= curve[bin]; 628 if (bin < cs) value *= curve[bin];
600 float norm = 0.f; 629 float norm = 0.f;
601 float y = getYForValue(value, v, norm); // don't need y, need norm 630 float y = getYForValue(value, v, norm); // don't need y, need norm
602 631
603 paint.setPen(mapper.map(norm)); 632 paint.setPen(mapper.map(norm));
604 paint.drawLine(xorigin + x, 0, xorigin + x, v->height()); 633 paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1);
605 } 634 }
606 635
607 paint.restore(); 636 paint.restore();
608 } 637 }
609 638
610 SliceLayer::paint(v, paint, rect); 639 SliceLayer::paint(v, paint, rect);
640
641 //!!! All of this stuff relating to depicting frequencies
642 //(keyboard, crosshairs etc) should be applicable to any slice
643 //layer whose model has a vertical scale unit of Hz. However, the
644 //dense 3d model at the moment doesn't record its vertical scale
645 //unit -- we need to fix that and hoist this code as appropriate.
646 //Same really goes for any code in SpectrogramLayer that could be
647 //relevant to Colour3DPlotLayer with unit Hz, but that's a bigger
648 //proposition.
611 649
612 if (m_binScale == LogBins) { 650 if (m_binScale == LogBins) {
613 651
614 int pkh = 10; 652 int pkh = 10;
615 int h = v->height(); 653 int h = v->height();
616 654
617 // piano keyboard 655 // piano keyboard
618 //!!! should be in a new paintHorizontalScale()? 656 //!!! should be in a new paintHorizontalScale()?
619 657 // nice to have a piano keyboard class, of course
620 paint.drawLine(xorigin, h - pkh - 1, w, h - pkh - 1); 658
659 paint.drawLine(xorigin, h - pkh - 1, w + xorigin, h - pkh - 1);
621 660
622 int px = xorigin, ppx = xorigin; 661 int px = xorigin, ppx = xorigin;
623 // paint.setBrush(paint.pen().color()); 662 paint.setBrush(paint.pen().color());
624 663
625 for (int i = 0; i < 128; ++i) { 664 for (int i = 0; i < 128; ++i) {
626 665
627 float f = Pitch::getFrequencyForPitch(i); 666 float f = Pitch::getFrequencyForPitch(i);
628 int x = lrintf(getXForFrequency(f, w)); 667 int x = lrintf(getXForFrequency(f, w));
629 668
630 if (x < 0) break; 669 x += xorigin;
631 if (x + xorigin > w) { 670
671 if (i == 0) {
672 px = ppx = x;
673 }
674 if (i == 1) {
675 ppx = px - (x - px);
676 }
677
678 if (x < xorigin) {
679 ppx = px;
680 px = x;
632 continue; 681 continue;
633 } 682 }
634 683
635 x += xorigin; 684 if (x > w) {
685 break;
686 }
636 687
637 int n = (i % 12); 688 int n = (i % 12);
638 689
639 if (n == 1) { 690 if (n == 1) {
640 // C# -- fill the C from here 691 // C# -- fill the C from here
641 if (x - ppx > 2) { 692 if (x - ppx > 2) {
642 paint.fillRect(x, 693 paint.fillRect((px + ppx) / 2 + 1,
643 h - pkh, 694 h - pkh,
644 x - (px + ppx) / 2, 695 x - (px + ppx) / 2 - 1,
645 pkh, 696 pkh,
646 Qt::gray); 697 Qt::gray);
647 } 698 }
648 } 699 }
649 700
650 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) { 701 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) {
651 // black notes 702 // black notes
652 paint.drawLine(x, h - pkh, x, h); 703 paint.drawLine(x, h - pkh, x, h);
653 int rw = ((px - x) / 4) * 2; 704 int rw = lrintf(float(x - px) / 4) * 2;
654 if (rw < 2) rw = 2; 705 if (rw < 2) rw = 2;
655 paint.drawRect(x - (px-x)/4, h - pkh, rw, pkh/2); 706 paint.drawRect(x - rw/2, h - pkh, rw, pkh/2);
656 } else if (n == 0 || n == 5) { 707 } else if (n == 0 || n == 5) {
657 // C, F 708 // C, F
658 if (px < w) { 709 if (px < w) {
659 paint.drawLine((x + px) / 2, h - pkh, (x + px) / 2, h); 710 paint.drawLine((x + px) / 2, h - pkh, (x + px) / 2, h);
660 } 711 }