comparison layer/WaveformLayer.cpp @ 68:193b569a975f

* Add scale lines to waveform layer * Various fixes to vertical scale drawing for waveform and time-value layers * Make log/linear scale have an effect for time-value layer segmentation mode
author Chris Cannam
date Wed, 29 Mar 2006 16:24:25 +0000
parents c4fff27cd651
children 6dad2724f3aa
comparison
equal deleted inserted replaced
67:c4fff27cd651 68:193b569a975f
76 PropertyList list; 76 PropertyList list;
77 list.push_back(tr("Colour")); 77 list.push_back(tr("Colour"));
78 list.push_back(tr("Scale")); 78 list.push_back(tr("Scale"));
79 list.push_back(tr("Gain")); 79 list.push_back(tr("Gain"));
80 list.push_back(tr("Normalize Visible Area")); 80 list.push_back(tr("Normalize Visible Area"));
81 list.push_back(tr("Channels")); 81
82 if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) {
83 list.push_back(tr("Channels"));
84 }
85
82 return list; 86 return list;
83 } 87 }
84 88
85 Layer::PropertyType 89 Layer::PropertyType
86 WaveformLayer::getPropertyType(const PropertyName &name) const 90 WaveformLayer::getPropertyType(const PropertyName &name) const
367 WaveformLayer::isLayerScrollable(const View *) const 371 WaveformLayer::isLayerScrollable(const View *) const
368 { 372 {
369 return !m_autoNormalize; 373 return !m_autoNormalize;
370 } 374 }
371 375
376 static float meterdbs[] = { -40, -30, -20, -15, -10,
377 -5, -3, -2, -1, -0.5, 0 };
378
372 void 379 void
373 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const 380 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const
374 { 381 {
375 if (!m_model || !m_model->isOK()) { 382 if (!m_model || !m_model->isOK()) {
376 return; 383 return;
484 491
485 for (size_t ch = minChannel; ch <= maxChannel; ++ch) { 492 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
486 493
487 int prevRangeBottom = -1, prevRangeTop = -1; 494 int prevRangeBottom = -1, prevRangeTop = -1;
488 QColor prevRangeBottomColour = m_colour, prevRangeTopColour = m_colour; 495 QColor prevRangeBottomColour = m_colour, prevRangeTopColour = m_colour;
489
490 int m = (h / channels) / 2;
491 int my = m + (((ch - minChannel) * h) / channels);
492
493 // std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl;
494
495 if (my - m > y1 || my + m < y0) continue;
496
497 paint->setPen(greys[0]);
498 paint->drawLine(x0, my, x1, my);
499
500 if (frame1 <= 0) continue;
501
502 size_t modelZoomLevel = zoomLevel;
503
504 ranges = m_model->getRanges
505 (ch, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
506
507 if (mergingChannels || mixingChannels) {
508 otherChannelRanges = m_model->getRanges
509 (1, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
510 }
511 496
512 m_effectiveGains[ch] = m_gain; 497 m_effectiveGains[ch] = m_gain;
513 498
514 if (m_autoNormalize) { 499 if (m_autoNormalize) {
515 RangeSummarisableTimeValueModel::Range range = 500 RangeSummarisableTimeValueModel::Range range =
526 m_effectiveGains[ch] = 1.0 / std::max(fabsf(range.max), 511 m_effectiveGains[ch] = 1.0 / std::max(fabsf(range.max),
527 fabsf(range.min)); 512 fabsf(range.min));
528 } 513 }
529 514
530 float gain = m_effectiveGains[ch]; 515 float gain = m_effectiveGains[ch];
516
517 int m = (h / channels) / 2;
518 int my = m + (((ch - minChannel) * h) / channels);
519
520 // std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl;
521
522 if (my - m > y1 || my + m < y0) continue;
523
524 if ((m_scale == dBScale || m_scale == MeterScale) &&
525 m_channelMode != MergeChannels) {
526 m = (h / channels);
527 my = m + (((ch - minChannel) * h) / channels);
528 }
529
530 paint->setPen(greys[0]);
531 paint->drawLine(x0, my, x1, my);
532
533 int n = 10;
534 int py = -1;
535
536 if (v->hasLightBackground()) {
537
538 paint->setPen(QColor(240, 240, 240));
539
540 for (int i = 1; i < n; ++i) {
541
542 float val = 0.0, nval = 0.0;
543
544 switch (m_scale) {
545
546 case LinearScale:
547 val = (i * gain) / n;
548 if (i > 0) nval = -val;
549 break;
550
551 case MeterScale:
552 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
553 break;
554
555 case dBScale:
556 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
557 break;
558 }
559
560 if (val < -1.0 || val > 1.0) continue;
561
562 int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
563
564 if (py >= 0 && abs(y - py) < 10) continue;
565 else py = y;
566
567 int ny = y;
568 if (nval != 0.0) {
569 ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
570 }
571
572 paint->drawLine(x0, y, x1, y);
573 if (ny != y) {
574 paint->drawLine(x0, ny, x1, ny);
575 }
576 }
577 }
578
579 if (frame1 <= 0) continue;
580
581 size_t modelZoomLevel = zoomLevel;
582
583 ranges = m_model->getRanges
584 (ch, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
585
586 if (mergingChannels || mixingChannels) {
587 otherChannelRanges = m_model->getRanges
588 (1, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
589 }
531 590
532 for (int x = x0; x <= x1; ++x) { 591 for (int x = x0; x <= x1; ++x) {
533 592
534 range = RangeSummarisableTimeValueModel::Range(); 593 range = RangeSummarisableTimeValueModel::Range();
535 size_t index = x - x0; 594 size_t index = x - x0;
830 889
831 return text; 890 return text;
832 } 891 }
833 892
834 int 893 int
894 WaveformLayer::getYForValue(View *v, Scale scale, float value, size_t channel,
895 size_t minChannel, size_t maxChannel) const
896 {
897 if (maxChannel < minChannel || channel < minChannel) return 0;
898
899 int w = v->width();
900 int h = v->height();
901
902 int channels = maxChannel - minChannel + 1;
903 int m = (h / channels) / 2;
904 int my = m + (((channel - minChannel) * h) / channels);
905
906 if ((m_scale == dBScale || m_scale == MeterScale) &&
907 m_channelMode != MergeChannels) {
908 m = (h / channels);
909 my = m + (((channel - minChannel) * h) / channels);
910 }
911
912 int vy = 0;
913
914 switch (scale) {
915
916 case LinearScale:
917 vy = int(m * value);
918 break;
919
920 case MeterScale:
921 vy = AudioLevel::multiplier_to_preview(value, m);
922 break;
923
924 case dBScale:
925 vy = dBscale(value, m);
926 break;
927 }
928
929 return my - vy;
930 }
931
932 int
835 WaveformLayer::getVerticalScaleWidth(View *v, QPainter &paint) const 933 WaveformLayer::getVerticalScaleWidth(View *v, QPainter &paint) const
836 { 934 {
837 if (m_scale == LinearScale) { 935 if (m_scale == LinearScale) {
838 return paint.fontMetrics().width("0.0") + 13; 936 return paint.fontMetrics().width("0.0") + 13;
839 } else { 937 } else {
862 960
863 float gain = m_gain; 961 float gain = m_gain;
864 962
865 for (size_t ch = minChannel; ch <= maxChannel; ++ch) { 963 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
866 964
867 int m = (h / channels) / 2; 965 int lastLabelledY = -1;
868 int my = m + (((ch - minChannel) * h) / channels);
869 int py = -1;
870 966
871 if (ch < m_effectiveGains.size()) gain = m_effectiveGains[ch]; 967 if (ch < m_effectiveGains.size()) gain = m_effectiveGains[ch];
872 968
873 for (int i = 0; i <= 10; ++i) { 969 int n = 10;
874 970
875 int vy = 0; 971 for (int i = 0; i <= n; ++i) {
972
973 float val = 0.0, nval = 0.0;
876 QString text = ""; 974 QString text = "";
877 975
878 if (m_scale == LinearScale) { 976 switch (m_scale) {
879 977
880 vy = int((m * i * gain) / 10); 978 case LinearScale:
881 979 val = (i * gain) / n;
882 text = QString("%1").arg(float(i) / 10.0); 980 text = QString("%1").arg(float(i) / n);
883 if (i == 0) text = "0.0"; 981 if (i == 0) text = "0.0";
884 if (i == 10) text = "1.0"; 982 else {
885 983 nval = -val;
886 } else { 984 if (i == n) text = "1.0";
887 985 }
888 int db; 986 break;
889 bool minvalue = false; 987
890 988 case MeterScale:
891 if (m_scale == MeterScale) { 989 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
892 static int dbs[] = { -50, -40, -30, -20, -15, 990 text = QString("%1").arg(meterdbs[i]);
893 -10, -5, -3, -2, -1, 0 }; 991 if (i == n) text = tr("0dB");
894 db = dbs[i]; 992 if (i == 0) {
895 if (db == -50) minvalue = true; 993 text = tr("-Inf");
896 vy = AudioLevel::multiplier_to_preview 994 val = 0.0;
897 (AudioLevel::dB_to_multiplier(db) * gain, m);
898 } else {
899 db = -100 + i * 10;
900 if (db == -100) minvalue = true;
901 vy = dBscale
902 (AudioLevel::dB_to_multiplier(db) * gain, m);
903 } 995 }
904 996 break;
905 text = QString("%1").arg(db); 997
906 if (db == 0) text = tr("0dB"); 998 case dBScale:
907 if (minvalue) { 999 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
908 text = tr("-Inf"); 1000 text = QString("%1").arg(-(10*n) + i * 10);
909 vy = 0; 1001 if (i == n) text = tr("0dB");
1002 if (i == 0) {
1003 text = tr("-Inf");
1004 val = 0.0;
910 } 1005 }
911 } 1006 break;
912 1007 }
913 if (vy < 0) vy = -vy; 1008
914 // if (vy >= m - 1) continue; 1009 if (val < -1.0 || val > 1.0) continue;
915 1010
916 if (py >= 0 && (vy - py) < textHeight - 1) { 1011 int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
917 paint.drawLine(w - 4, my - vy, w, my - vy); 1012
918 if (vy > 0) paint.drawLine(w - 4, my + vy, w, my + vy); 1013 int ny = y;
919 continue; 1014 if (nval != 0.0) {
920 } 1015 ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
921 1016 }
922 paint.drawLine(w - 7, my - vy, w, my - vy); 1017
923 if (vy > 0) paint.drawLine(w - 7, my + vy, w, my + vy); 1018 bool spaceForLabel = (i == 0 ||
924 1019 abs(y - lastLabelledY) >= textHeight - 1);
925 int tx = 3; 1020
926 if (m_scale != LinearScale) { 1021 if (spaceForLabel) {
927 tx = w - 10 - paint.fontMetrics().width(text); 1022
928 } 1023 int tx = 3;
929 1024 if (m_scale != LinearScale) {
930 if (vy >= m - 1) continue; 1025 tx = w - 10 - paint.fontMetrics().width(text);
931 1026 }
932 paint.drawText(tx, my - vy + toff, text); 1027
933 if (vy > 0) paint.drawText(tx, my + vy + toff, text); 1028 int ty = y;
934 1029 if (ty < paint.fontMetrics().ascent()) {
935 py = vy; 1030 ty = paint.fontMetrics().ascent();
1031 } else if (ty > h - paint.fontMetrics().descent()) {
1032 ty = h - paint.fontMetrics().descent();
1033 } else {
1034 ty += toff;
1035 }
1036 paint.drawText(tx, ty, text);
1037
1038 lastLabelledY = ty - toff;
1039
1040 if (ny != y) {
1041 ty = ny;
1042 if (ty < paint.fontMetrics().ascent()) {
1043 ty = paint.fontMetrics().ascent();
1044 } else if (ty > h - paint.fontMetrics().descent()) {
1045 ty = h - paint.fontMetrics().descent();
1046 } else {
1047 ty += toff;
1048 }
1049 paint.drawText(tx, ty, text);
1050 }
1051
1052 paint.drawLine(w - 7, y, w, y);
1053 if (ny != y) paint.drawLine(w - 7, ny, w, ny);
1054
1055 } else {
1056
1057 paint.drawLine(w - 4, y, w, y);
1058 if (ny != y) paint.drawLine(w - 4, ny, w, ny);
1059 }
936 } 1060 }
937 } 1061 }
938 } 1062 }
939 1063
940 QString 1064 QString