comparison layer/WaveformLayer.cpp @ 365:26ce2fb7bcbf

* Ensure waveforms are strictly correct even when using a non-power-of-two non-power-of-sqrt-two block size with cacheing off and painting only small areas at a time
author Chris Cannam
date Thu, 07 Feb 2008 15:25:05 +0000
parents a9dfa2d6d5ac
children e1a9e478b7f2
comparison
equal deleted inserted replaced
364:f1e6204c1f17 365:26ce2fb7bcbf
394 } 394 }
395 395
396 static float meterdbs[] = { -40, -30, -20, -15, -10, 396 static float meterdbs[] = { -40, -30, -20, -15, -10,
397 -5, -3, -2, -1, -0.5, 0 }; 397 -5, -3, -2, -1, -0.5, 0 };
398 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
399 void 466 void
400 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const 467 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const
401 { 468 {
402 if (!m_model || !m_model->isOK()) { 469 if (!m_model || !m_model->isOK()) {
403 return; 470 return;
404 } 471 }
405 472
406 long startFrame = v->getStartFrame();
407 long endFrame = v->getEndFrame();
408 int zoomLevel = v->getZoomLevel(); 473 int zoomLevel = v->getZoomLevel();
409 474
410 #ifdef DEBUG_WAVEFORM_PAINT 475 #ifdef DEBUG_WAVEFORM_PAINT
411 Profiler profiler("WaveformLayer::paint", true); 476 Profiler profiler("WaveformLayer::paint", true);
412 std::cerr << "WaveformLayer::paint (" << rect.x() << "," << rect.y() 477 std::cerr << "WaveformLayer::paint (" << rect.x() << "," << rect.y()
476 y1 = rect.bottom(); 541 y1 = rect.bottom();
477 542
478 if (x0 > 0) --x0; 543 if (x0 > 0) --x0;
479 if (x1 < v->width()) ++x1; 544 if (x1 < v->width()) ++x1;
480 545
481 long frame0 = v->getFrameForX(x0); 546 // Our zoom level may differ from that at which the underlying
482 long frame1 = v->getFrameForX(x1 + 1); 547 // model has its blocks.
483 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
484 #ifdef DEBUG_WAVEFORM_PAINT 564 #ifdef DEBUG_WAVEFORM_PAINT
485 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;
486 #endif 566 #endif
487 567
488 RangeSummarisableTimeValueModel::RangeBlock *ranges = 568 RangeSummarisableTimeValueModel::RangeBlock *ranges =
489 new RangeSummarisableTimeValueModel::RangeBlock; 569 new RangeSummarisableTimeValueModel::RangeBlock;
490 570
505 585
506 while (m_effectiveGains.size() <= maxChannel) { 586 while (m_effectiveGains.size() <= maxChannel) {
507 m_effectiveGains.push_back(m_gain); 587 m_effectiveGains.push_back(m_gain);
508 } 588 }
509 589
510 // Although a long for purposes of comparison against the view
511 // start and end frames, these are known to be non-negative
512 long modelStart = long(m_model->getStartFrame());
513 long modelEnd = long(m_model->getEndFrame());
514
515 #ifdef DEBUG_WAVEFORM_PAINT
516 std::cerr << "Model start = " << modelStart << ", end = " << modelEnd << std::endl;
517 #endif
518
519 for (size_t ch = minChannel; ch <= maxChannel; ++ch) { 590 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
520 591
521 int prevRangeBottom = -1, prevRangeTop = -1; 592 int prevRangeBottom = -1, prevRangeTop = -1;
522 QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour; 593 QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour;
523 size_t rangeStart, rangeEnd;
524 594
525 m_effectiveGains[ch] = m_gain; 595 m_effectiveGains[ch] = m_gain;
526 596
527 if (m_autoNormalize) { 597 if (m_autoNormalize) {
528 598 m_effectiveGains[ch] = getNormalizeGain(v, ch);
529 if (startFrame < modelStart) rangeStart = modelStart;
530 else rangeStart = startFrame;
531
532 if (endFrame < 0) rangeEnd = 0;
533 else if (endFrame > modelEnd) rangeEnd = modelEnd;
534 else rangeEnd = endFrame;
535
536 if (rangeEnd < rangeStart) rangeEnd = rangeStart;
537
538 RangeSummarisableTimeValueModel::Range range =
539 m_model->getSummary(ch, rangeStart, rangeEnd - rangeStart);
540 if (mergingChannels || mixingChannels) {
541 RangeSummarisableTimeValueModel::Range otherRange =
542 m_model->getSummary(1, rangeStart, rangeEnd - rangeStart);
543 range.max = std::max(range.max, otherRange.max);
544 range.min = std::min(range.min, otherRange.min);
545 range.absmean = std::min(range.absmean, otherRange.absmean);
546 }
547 m_effectiveGains[ch] = 1.0 / std::max(fabsf(range.max),
548 fabsf(range.min));
549 } 599 }
550 600
551 float gain = m_effectiveGains[ch]; 601 float gain = m_effectiveGains[ch];
552 602
553 int m = (h / channels) / 2; 603 int m = (h / channels) / 2;
611 if (ny != y) { 661 if (ny != y) {
612 paint->drawLine(x0, ny, x1, ny); 662 paint->drawLine(x0, ny, x1, ny);
613 } 663 }
614 } 664 }
615 } 665 }
616 666
617 if (frame1 < modelStart) continue; 667 m_model->getSummaries(ch, frame0, frame1 - frame0,
618 668 *ranges, modelZoomLevel);
619 size_t modelZoomLevel = zoomLevel; 669
620 670 #ifdef DEBUG_WAVEFORM_PAINT
621 if (frame0 < modelStart) rangeStart = modelStart; 671 std::cerr << ranges->size() << " ranges from " << frame0 << " to " << frame1 << std::endl;
622 else rangeStart = frame0; 672 #endif
623 673
624 if (frame1 < 0) rangeEnd = 0;
625 else if (frame1 > modelEnd) rangeEnd = modelEnd;
626 else rangeEnd = frame1;
627
628 if (rangeEnd < rangeStart) rangeEnd = rangeStart;
629
630 m_model->getSummaries
631 (ch, rangeStart, rangeEnd - rangeStart, *ranges, modelZoomLevel);
632
633 // std::cerr << ranges->size() << " ranges" << std::endl;
634
635 if (mergingChannels || mixingChannels) { 674 if (mergingChannels || mixingChannels) {
636 if (m_model->getChannelCount() > 1) { 675 if (m_model->getChannelCount() > 1) {
637 if (!otherChannelRanges) { 676 if (!otherChannelRanges) {
638 otherChannelRanges = 677 otherChannelRanges =
639 new RangeSummarisableTimeValueModel::RangeBlock; 678 new RangeSummarisableTimeValueModel::RangeBlock;
640 } 679 }
641 m_model->getSummaries 680 m_model->getSummaries
642 (1, rangeStart, rangeEnd - rangeStart, *otherChannelRanges, 681 (1, frame0, frame1 - frame0, *otherChannelRanges,
643 modelZoomLevel); 682 modelZoomLevel);
644 } else { 683 } else {
645 if (otherChannelRanges != ranges) delete otherChannelRanges; 684 if (otherChannelRanges != ranges) delete otherChannelRanges;
646 otherChannelRanges = ranges; 685 otherChannelRanges = ranges;
647 } 686 }
648 } 687 }
649 688
650 for (int x = x0; x <= x1; ++x) { 689 for (int x = x0; x <= x1; ++x) {
651 690
652 range = RangeSummarisableTimeValueModel::Range(); 691 range = RangeSummarisableTimeValueModel::Range();
653 size_t index = x - x0; 692
654 size_t maxIndex = index; 693 size_t f0, f1;
655 694 if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) continue;
656 if (frame0 < modelStart) { 695 f1 = f1 - 1;
657 if (index < size_t((modelStart - frame0) / zoomLevel)) { 696
658 continue; 697 if (f0 < frame0) {
659 } else { 698 std::cerr << "ERROR: WaveformLayer::paint: pixel " << x << " has f0 = " << f0 << " which is less than range frame0 " << frame0 << " for x0 = " << x0 << std::endl;
660 index -= ((modelStart - frame0) / zoomLevel); 699 continue;
661 maxIndex = index;
662 }
663 } 700 }
664 701
665 if (int(modelZoomLevel) != zoomLevel) { 702 size_t i0 = (f0 - frame0) / modelZoomLevel;
666 703 size_t i1 = (f1 - frame0) / modelZoomLevel;
667 std::cerr << "WaveformLayer::paint: zoom level " << zoomLevel << " differs from model zoom level " << modelZoomLevel << std::endl; 704
668 std::cerr << "index from " << index; 705 #ifdef DEBUG_WAVEFORM_PAINT
669 706 std::cerr << "WaveformLayer::paint: pixel " << x << ": i0 " << i0 << " (f " << f0 << "), i1 " << i1 << " (f " << f1 << ")" << std::endl;
670 index = size_t((double(index) * zoomLevel) / modelZoomLevel); 707 #endif
671 708
672 std::cerr << " to " << index << std::endl; 709 if (i1 > i0 + 1) {
673 710 std::cerr << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << zoomLevel << ", model zoom = " << modelZoomLevel << ")" << std::endl;
674 if (int(modelZoomLevel) < zoomLevel) { 711 }
675 // Peaks may be missed! The model should avoid 712
676 // this by rounding zoom levels up rather than 713 if (ranges && i0 < ranges->size()) {
677 // down, but we'd better cope in case it doesn't 714
678 maxIndex = index; 715 range = (*ranges)[i0];
679 } else { 716
680 maxIndex = size_t((double(index + 1) * zoomLevel) 717 if (i1 > i0 && i1 < ranges->size()) {
681 / modelZoomLevel) - 1; 718 range.max = std::max(range.max, (*ranges)[i1].max);
682 } 719 range.min = std::min(range.min, (*ranges)[i1].min);
683 720 range.absmean = (range.absmean + (*ranges)[i1].absmean) / 2;
684 std::cerr << "maxIndex = " << maxIndex << std::endl;
685 }
686
687 if (ranges && index < ranges->size()) {
688
689 range = (*ranges)[index];
690
691 if (maxIndex > index && maxIndex < ranges->size()) {
692 range.max = std::max(range.max, (*ranges)[maxIndex].max);
693 range.min = std::min(range.min, (*ranges)[maxIndex].min);
694 range.absmean = (range.absmean +
695 (*ranges)[maxIndex].absmean) / 2;
696 } 721 }
697 722
698 } else { 723 } else {
699 continue; 724 continue;
700 } 725 }
701 726
702 int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0; 727 int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0;
703 728
704 if (mergingChannels) { 729 if (mergingChannels) {
705 730
706 if (otherChannelRanges && index < otherChannelRanges->size()) { 731 if (otherChannelRanges && i0 < otherChannelRanges->size()) {
707 732
708 range.max = fabsf(range.max); 733 range.max = fabsf(range.max);
709 range.min = -fabsf((*otherChannelRanges)[index].max); 734 range.min = -fabsf((*otherChannelRanges)[i0].max);
710 range.absmean = (range.absmean + 735 range.absmean = (range.absmean +
711 (*otherChannelRanges)[index].absmean) / 2; 736 (*otherChannelRanges)[i0].absmean) / 2;
712 737
713 if (maxIndex > index && maxIndex < otherChannelRanges->size()) { 738 if (i1 > i0 && i1 < otherChannelRanges->size()) {
714 // let's not concern ourselves about the mean 739 // let's not concern ourselves about the mean
715 range.min = std::min 740 range.min = std::min
716 (range.min, 741 (range.min,
717 -fabsf((*otherChannelRanges)[maxIndex].max)); 742 -fabsf((*otherChannelRanges)[i1].max));
718 } 743 }
719 } 744 }
720 745
721 } else if (mixingChannels) { 746 } else if (mixingChannels) {
722 747
723 if (otherChannelRanges && index < otherChannelRanges->size()) { 748 if (otherChannelRanges && i0 < otherChannelRanges->size()) {
724 749
725 range.max = (range.max + (*otherChannelRanges)[index].max) / 2; 750 range.max = (range.max + (*otherChannelRanges)[i0].max) / 2;
726 range.min = (range.min + (*otherChannelRanges)[index].min) / 2; 751 range.min = (range.min + (*otherChannelRanges)[i0].min) / 2;
727 range.absmean = (range.absmean + (*otherChannelRanges)[index].absmean) / 2; 752 range.absmean = (range.absmean + (*otherChannelRanges)[i0].absmean) / 2;
728 } 753 }
729 } 754 }
730 755
731 int greyLevels = 1; 756 int greyLevels = 1;
732 if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4; 757 if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4;
895 { 920 {
896 int x = pos.x(); 921 int x = pos.x();
897 922
898 if (!m_model || !m_model->isOK()) return ""; 923 if (!m_model || !m_model->isOK()) return "";
899 924
900 long f0 = v->getFrameForX(x); 925 int zoomLevel = v->getZoomLevel();
901 long f1 = v->getFrameForX(x + 1); 926
902 927 size_t modelZoomLevel = m_model->getSummaryBlockSize(zoomLevel);
903 if (f0 < 0) f0 = 0; 928
904 if (f1 <= f0) return ""; 929 size_t f0, f1;
930 if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) return "";
905 931
906 QString text; 932 QString text;
907 933
908 RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate()); 934 RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate());
909 RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate()); 935 RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate());