Mercurial > hg > svgui
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 } |