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