Mercurial > hg > svgui
comparison layer/WaveformLayer.cpp @ 374:64e84e5efb76 spectrogram-cache-rejig
* Merge from trunk
author | Chris Cannam |
---|---|
date | Wed, 27 Feb 2008 11:59:42 +0000 |
parents | 1f67b110c1a3 |
children |
comparison
equal
deleted
inserted
replaced
332:6440e280122e | 374:64e84e5efb76 |
---|---|
104 if (name == "Scale") return tr("Scale"); | 104 if (name == "Scale") return tr("Scale"); |
105 if (name == "Gain") return tr("Gain"); | 105 if (name == "Gain") return tr("Gain"); |
106 if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); | 106 if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); |
107 if (name == "Channels") return tr("Channels"); | 107 if (name == "Channels") return tr("Channels"); |
108 return SingleColourLayer::getPropertyLabel(name); | 108 return SingleColourLayer::getPropertyLabel(name); |
109 } | |
110 | |
111 QString | |
112 WaveformLayer::getPropertyIconName(const PropertyName &name) const | |
113 { | |
114 if (name == "Normalize Visible Area") return "normalise"; | |
115 return ""; | |
109 } | 116 } |
110 | 117 |
111 Layer::PropertyType | 118 Layer::PropertyType |
112 WaveformLayer::getPropertyType(const PropertyName &name) const | 119 WaveformLayer::getPropertyType(const PropertyName &name) const |
113 { | 120 { |
387 } | 394 } |
388 | 395 |
389 static float meterdbs[] = { -40, -30, -20, -15, -10, | 396 static float meterdbs[] = { -40, -30, -20, -15, -10, |
390 -5, -3, -2, -1, -0.5, 0 }; | 397 -5, -3, -2, -1, -0.5, 0 }; |
391 | 398 |
399 bool | |
400 WaveformLayer::getSourceFramesForX(View *v, int x, size_t modelZoomLevel, | |
401 size_t &f0, size_t &f1) const | |
402 { | |
403 long viewFrame = v->getFrameForX(x); | |
404 if (viewFrame < 0) { | |
405 f0 = 0; | |
406 f1 = 0; | |
407 return false; | |
408 } | |
409 | |
410 f0 = viewFrame; | |
411 | |
412 f0 = f0 / modelZoomLevel; | |
413 f0 = f0 * modelZoomLevel; | |
414 | |
415 viewFrame = v->getFrameForX(x + 1); | |
416 | |
417 f1 = viewFrame; | |
418 f1 = f1 / modelZoomLevel; | |
419 f1 = f1 * modelZoomLevel; | |
420 | |
421 return (f0 < m_model->getEndFrame()); | |
422 } | |
423 | |
424 float | |
425 WaveformLayer::getNormalizeGain(View *v, int channel) const | |
426 { | |
427 long startFrame = v->getStartFrame(); | |
428 long endFrame = v->getEndFrame(); | |
429 | |
430 // Although a long for purposes of comparison against the view | |
431 // start and end frames, these are known to be non-negative | |
432 long modelStart = long(m_model->getStartFrame()); | |
433 long modelEnd = long(m_model->getEndFrame()); | |
434 | |
435 size_t rangeStart, rangeEnd; | |
436 | |
437 if (startFrame < modelStart) rangeStart = modelStart; | |
438 else rangeStart = startFrame; | |
439 | |
440 if (endFrame < 0) rangeEnd = 0; | |
441 else if (endFrame > modelEnd) rangeEnd = modelEnd; | |
442 else rangeEnd = endFrame; | |
443 | |
444 if (rangeEnd < rangeStart) rangeEnd = rangeStart; | |
445 | |
446 RangeSummarisableTimeValueModel::Range range = | |
447 m_model->getSummary(channel, rangeStart, rangeEnd - rangeStart); | |
448 | |
449 size_t minChannel = 0, maxChannel = 0; | |
450 bool mergingChannels = false, mixingChannels = false; | |
451 | |
452 getChannelArrangement(minChannel, maxChannel, | |
453 mergingChannels, mixingChannels); | |
454 | |
455 if (mergingChannels || mixingChannels) { | |
456 RangeSummarisableTimeValueModel::Range otherRange = | |
457 m_model->getSummary(1, rangeStart, rangeEnd - rangeStart); | |
458 range.max = std::max(range.max, otherRange.max); | |
459 range.min = std::min(range.min, otherRange.min); | |
460 range.absmean = std::min(range.absmean, otherRange.absmean); | |
461 } | |
462 | |
463 return 1.0 / std::max(fabsf(range.max), fabsf(range.min)); | |
464 } | |
465 | |
392 void | 466 void |
393 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const | 467 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const |
394 { | 468 { |
395 if (!m_model || !m_model->isOK()) { | 469 if (!m_model || !m_model->isOK()) { |
396 return; | 470 return; |
397 } | 471 } |
398 | 472 |
399 long startFrame = v->getStartFrame(); | |
400 long endFrame = v->getEndFrame(); | |
401 int zoomLevel = v->getZoomLevel(); | 473 int zoomLevel = v->getZoomLevel(); |
402 | 474 |
403 #ifdef DEBUG_WAVEFORM_PAINT | 475 #ifdef DEBUG_WAVEFORM_PAINT |
404 Profiler profiler("WaveformLayer::paint", true); | 476 Profiler profiler("WaveformLayer::paint", true); |
405 std::cerr << "WaveformLayer::paint (" << rect.x() << "," << rect.y() | 477 std::cerr << "WaveformLayer::paint (" << rect.x() << "," << rect.y() |
469 y1 = rect.bottom(); | 541 y1 = rect.bottom(); |
470 | 542 |
471 if (x0 > 0) --x0; | 543 if (x0 > 0) --x0; |
472 if (x1 < v->width()) ++x1; | 544 if (x1 < v->width()) ++x1; |
473 | 545 |
474 long frame0 = v->getFrameForX(x0); | 546 // Our zoom level may differ from that at which the underlying |
475 long frame1 = v->getFrameForX(x1 + 1); | 547 // model has its blocks. |
476 | 548 |
549 // Each pixel within our visible range must always draw from | |
550 // exactly the same set of underlying audio frames, no matter what | |
551 // the range being drawn is. And that set of underlying frames | |
552 // must remain the same when we scroll one or more pixels left or | |
553 // right. | |
554 | |
555 size_t modelZoomLevel = m_model->getSummaryBlockSize(zoomLevel); | |
556 | |
557 size_t frame0; | |
558 size_t frame1; | |
559 size_t spare; | |
560 | |
561 getSourceFramesForX(v, x0, modelZoomLevel, frame0, spare); | |
562 getSourceFramesForX(v, x1, modelZoomLevel, spare, frame1); | |
563 | |
477 #ifdef DEBUG_WAVEFORM_PAINT | 564 #ifdef DEBUG_WAVEFORM_PAINT |
478 std::cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << ")" << std::endl; | 565 std::cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << " and model zoom " << modelZoomLevel << ")" << std::endl; |
479 #endif | 566 #endif |
480 | 567 |
481 RangeSummarisableTimeValueModel::RangeBlock *ranges = | 568 RangeSummarisableTimeValueModel::RangeBlock *ranges = |
482 new RangeSummarisableTimeValueModel::RangeBlock; | 569 new RangeSummarisableTimeValueModel::RangeBlock; |
483 | 570 |
498 | 585 |
499 while (m_effectiveGains.size() <= maxChannel) { | 586 while (m_effectiveGains.size() <= maxChannel) { |
500 m_effectiveGains.push_back(m_gain); | 587 m_effectiveGains.push_back(m_gain); |
501 } | 588 } |
502 | 589 |
503 // Although a long for purposes of comparison against the view | |
504 // start and end frames, these are known to be non-negative | |
505 long modelStart = long(m_model->getStartFrame()); | |
506 long modelEnd = long(m_model->getEndFrame()); | |
507 | |
508 #ifdef DEBUG_WAVEFORM_PAINT | |
509 std::cerr << "Model start = " << modelStart << ", end = " << modelEnd << std::endl; | |
510 #endif | |
511 | |
512 for (size_t ch = minChannel; ch <= maxChannel; ++ch) { | 590 for (size_t ch = minChannel; ch <= maxChannel; ++ch) { |
513 | 591 |
514 int prevRangeBottom = -1, prevRangeTop = -1; | 592 int prevRangeBottom = -1, prevRangeTop = -1; |
515 QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour; | 593 QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour; |
516 size_t rangeStart, rangeEnd; | |
517 | 594 |
518 m_effectiveGains[ch] = m_gain; | 595 m_effectiveGains[ch] = m_gain; |
519 | 596 |
520 if (m_autoNormalize) { | 597 if (m_autoNormalize) { |
521 | 598 m_effectiveGains[ch] = getNormalizeGain(v, ch); |
522 if (startFrame < modelStart) rangeStart = modelStart; | |
523 else rangeStart = startFrame; | |
524 | |
525 if (endFrame < 0) rangeEnd = 0; | |
526 else if (endFrame > modelEnd) rangeEnd = modelEnd; | |
527 else rangeEnd = endFrame; | |
528 | |
529 if (rangeEnd < rangeStart) rangeEnd = rangeStart; | |
530 | |
531 RangeSummarisableTimeValueModel::Range range = | |
532 m_model->getSummary(ch, rangeStart, rangeEnd - rangeStart); | |
533 if (mergingChannels || mixingChannels) { | |
534 RangeSummarisableTimeValueModel::Range otherRange = | |
535 m_model->getSummary(1, rangeStart, rangeEnd - rangeStart); | |
536 range.max = std::max(range.max, otherRange.max); | |
537 range.min = std::min(range.min, otherRange.min); | |
538 range.absmean = std::min(range.absmean, otherRange.absmean); | |
539 } | |
540 m_effectiveGains[ch] = 1.0 / std::max(fabsf(range.max), | |
541 fabsf(range.min)); | |
542 } | 599 } |
543 | 600 |
544 float gain = m_effectiveGains[ch]; | 601 float gain = m_effectiveGains[ch]; |
545 | 602 |
546 int m = (h / channels) / 2; | 603 int m = (h / channels) / 2; |
604 if (ny != y) { | 661 if (ny != y) { |
605 paint->drawLine(x0, ny, x1, ny); | 662 paint->drawLine(x0, ny, x1, ny); |
606 } | 663 } |
607 } | 664 } |
608 } | 665 } |
609 | 666 |
610 if (frame1 < modelStart) continue; | 667 m_model->getSummaries(ch, frame0, frame1 - frame0, |
611 | 668 *ranges, modelZoomLevel); |
612 size_t modelZoomLevel = zoomLevel; | 669 |
613 | 670 #ifdef DEBUG_WAVEFORM_PAINT |
614 if (frame0 < modelStart) rangeStart = modelStart; | 671 std::cerr << ranges->size() << " ranges from " << frame0 << " to " << frame1 << std::endl; |
615 else rangeStart = frame0; | 672 #endif |
616 | 673 |
617 if (frame1 < 0) rangeEnd = 0; | |
618 else if (frame1 > modelEnd) rangeEnd = modelEnd; | |
619 else rangeEnd = frame1; | |
620 | |
621 if (rangeEnd < rangeStart) rangeEnd = rangeStart; | |
622 | |
623 m_model->getSummaries | |
624 (ch, rangeStart, rangeEnd - rangeStart, *ranges, modelZoomLevel); | |
625 | |
626 // std::cerr << ranges->size() << " ranges" << std::endl; | |
627 | |
628 if (mergingChannels || mixingChannels) { | 674 if (mergingChannels || mixingChannels) { |
629 if (m_model->getChannelCount() > 1) { | 675 if (m_model->getChannelCount() > 1) { |
630 if (!otherChannelRanges) { | 676 if (!otherChannelRanges) { |
631 otherChannelRanges = | 677 otherChannelRanges = |
632 new RangeSummarisableTimeValueModel::RangeBlock; | 678 new RangeSummarisableTimeValueModel::RangeBlock; |
633 } | 679 } |
634 m_model->getSummaries | 680 m_model->getSummaries |
635 (1, rangeStart, rangeEnd - rangeStart, *otherChannelRanges, | 681 (1, frame0, frame1 - frame0, *otherChannelRanges, |
636 modelZoomLevel); | 682 modelZoomLevel); |
637 } else { | 683 } else { |
638 if (otherChannelRanges != ranges) delete otherChannelRanges; | 684 if (otherChannelRanges != ranges) delete otherChannelRanges; |
639 otherChannelRanges = ranges; | 685 otherChannelRanges = ranges; |
640 } | 686 } |
641 } | 687 } |
642 | 688 |
643 for (int x = x0; x <= x1; ++x) { | 689 for (int x = x0; x <= x1; ++x) { |
644 | 690 |
645 range = RangeSummarisableTimeValueModel::Range(); | 691 range = RangeSummarisableTimeValueModel::Range(); |
646 size_t index = x - x0; | 692 |
647 size_t maxIndex = index; | 693 size_t f0, f1; |
648 | 694 if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) continue; |
649 if (frame0 < modelStart) { | 695 f1 = f1 - 1; |
650 if (index < size_t((modelStart - frame0) / zoomLevel)) { | 696 |
651 continue; | 697 if (f0 < frame0) { |
652 } else { | 698 std::cerr << "ERROR: WaveformLayer::paint: pixel " << x << " has f0 = " << f0 << " which is less than range frame0 " << frame0 << " for x0 = " << x0 << std::endl; |
653 index -= ((modelStart - frame0) / zoomLevel); | 699 continue; |
654 maxIndex = index; | |
655 } | |
656 } | 700 } |
657 | 701 |
658 if (int(modelZoomLevel) != zoomLevel) { | 702 size_t i0 = (f0 - frame0) / modelZoomLevel; |
659 | 703 size_t i1 = (f1 - frame0) / modelZoomLevel; |
660 index = size_t((double(index) * zoomLevel) / modelZoomLevel); | 704 |
661 | 705 #ifdef DEBUG_WAVEFORM_PAINT |
662 if (int(modelZoomLevel) < zoomLevel) { | 706 std::cerr << "WaveformLayer::paint: pixel " << x << ": i0 " << i0 << " (f " << f0 << "), i1 " << i1 << " (f " << f1 << ")" << std::endl; |
663 // Peaks may be missed! The model should avoid | 707 #endif |
664 // this by rounding zoom levels up rather than | 708 |
665 // down, but we'd better cope in case it doesn't | 709 if (i1 > i0 + 1) { |
666 maxIndex = index; | 710 std::cerr << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << zoomLevel << ", model zoom = " << modelZoomLevel << ")" << std::endl; |
667 } else { | 711 } |
668 maxIndex = size_t((double(index + 1) * zoomLevel) | 712 |
669 / modelZoomLevel) - 1; | 713 if (ranges && i0 < ranges->size()) { |
670 } | 714 |
671 } | 715 range = (*ranges)[i0]; |
672 | 716 |
673 if (ranges && index < ranges->size()) { | 717 if (i1 > i0 && i1 < ranges->size()) { |
674 | 718 range.max = std::max(range.max, (*ranges)[i1].max); |
675 range = (*ranges)[index]; | 719 range.min = std::min(range.min, (*ranges)[i1].min); |
676 | 720 range.absmean = (range.absmean + (*ranges)[i1].absmean) / 2; |
677 if (maxIndex > index && maxIndex < ranges->size()) { | |
678 range.max = std::max(range.max, (*ranges)[maxIndex].max); | |
679 range.min = std::min(range.min, (*ranges)[maxIndex].min); | |
680 range.absmean = (range.absmean + | |
681 (*ranges)[maxIndex].absmean) / 2; | |
682 } | 721 } |
683 | 722 |
684 } else { | 723 } else { |
685 continue; | 724 continue; |
686 } | 725 } |
687 | 726 |
688 int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0; | 727 int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0; |
689 | 728 |
690 if (mergingChannels) { | 729 if (mergingChannels) { |
691 | 730 |
692 if (otherChannelRanges && index < otherChannelRanges->size()) { | 731 if (otherChannelRanges && i0 < otherChannelRanges->size()) { |
693 | 732 |
694 range.max = fabsf(range.max); | 733 range.max = fabsf(range.max); |
695 range.min = -fabsf((*otherChannelRanges)[index].max); | 734 range.min = -fabsf((*otherChannelRanges)[i0].max); |
696 range.absmean = (range.absmean + | 735 range.absmean = (range.absmean + |
697 (*otherChannelRanges)[index].absmean) / 2; | 736 (*otherChannelRanges)[i0].absmean) / 2; |
698 | 737 |
699 if (maxIndex > index && maxIndex < otherChannelRanges->size()) { | 738 if (i1 > i0 && i1 < otherChannelRanges->size()) { |
700 // let's not concern ourselves about the mean | 739 // let's not concern ourselves about the mean |
701 range.min = std::min | 740 range.min = std::min |
702 (range.min, | 741 (range.min, |
703 -fabsf((*otherChannelRanges)[maxIndex].max)); | 742 -fabsf((*otherChannelRanges)[i1].max)); |
704 } | 743 } |
705 } | 744 } |
706 | 745 |
707 } else if (mixingChannels) { | 746 } else if (mixingChannels) { |
708 | 747 |
709 if (otherChannelRanges && index < otherChannelRanges->size()) { | 748 if (otherChannelRanges && i0 < otherChannelRanges->size()) { |
710 | 749 |
711 range.max = (range.max + (*otherChannelRanges)[index].max) / 2; | 750 range.max = (range.max + (*otherChannelRanges)[i0].max) / 2; |
712 range.min = (range.min + (*otherChannelRanges)[index].min) / 2; | 751 range.min = (range.min + (*otherChannelRanges)[i0].min) / 2; |
713 range.absmean = (range.absmean + (*otherChannelRanges)[index].absmean) / 2; | 752 range.absmean = (range.absmean + (*otherChannelRanges)[i0].absmean) / 2; |
714 } | 753 } |
715 } | 754 } |
716 | 755 |
717 int greyLevels = 1; | 756 int greyLevels = 1; |
718 if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4; | 757 if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4; |
881 { | 920 { |
882 int x = pos.x(); | 921 int x = pos.x(); |
883 | 922 |
884 if (!m_model || !m_model->isOK()) return ""; | 923 if (!m_model || !m_model->isOK()) return ""; |
885 | 924 |
886 long f0 = v->getFrameForX(x); | 925 int zoomLevel = v->getZoomLevel(); |
887 long f1 = v->getFrameForX(x + 1); | 926 |
888 | 927 size_t modelZoomLevel = m_model->getSummaryBlockSize(zoomLevel); |
889 if (f0 < 0) f0 = 0; | 928 |
890 if (f1 <= f0) return ""; | 929 size_t f0, f1; |
930 if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) return ""; | |
891 | 931 |
892 QString text; | 932 QString text; |
893 | 933 |
894 RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate()); | 934 RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate()); |
895 RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate()); | 935 RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate()); |