Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 119:508276c923ba
* Various experiments in spectrogram colour scaling, etc. Nothing final
here yet, but some promising developments.
author | Chris Cannam |
---|---|
date | Fri, 14 Jul 2006 17:12:16 +0000 |
parents | 853a7fc542d0 |
children | 8dfa20f1c70a |
comparison
equal
deleted
inserted
replaced
118:853a7fc542d0 | 119:508276c923ba |
---|---|
33 #include <iostream> | 33 #include <iostream> |
34 | 34 |
35 #include <cassert> | 35 #include <cassert> |
36 #include <cmath> | 36 #include <cmath> |
37 | 37 |
38 #define DEBUG_SPECTROGRAM_REPAINT 1 | 38 //#define DEBUG_SPECTROGRAM_REPAINT 1 |
39 | 39 |
40 SpectrogramLayer::SpectrogramLayer(Configuration config) : | 40 SpectrogramLayer::SpectrogramLayer(Configuration config) : |
41 Layer(), | 41 Layer(), |
42 m_model(0), | 42 m_model(0), |
43 m_channel(0), | 43 m_channel(0), |
47 m_zeroPadLevel(0), | 47 m_zeroPadLevel(0), |
48 m_fftSize(1024), | 48 m_fftSize(1024), |
49 m_gain(1.0), | 49 m_gain(1.0), |
50 m_threshold(0.0), | 50 m_threshold(0.0), |
51 m_colourRotation(0), | 51 m_colourRotation(0), |
52 m_minFrequency(0), | 52 m_minFrequency(10), |
53 m_maxFrequency(8000), | 53 m_maxFrequency(8000), |
54 m_colourScale(dBColourScale), | 54 m_colourScale(dBColourScale), |
55 m_colourScheme(DefaultColours), | 55 m_colourScheme(DefaultColours), |
56 m_frequencyScale(LinearFrequencyScale), | 56 m_frequencyScale(LinearFrequencyScale), |
57 m_binDisplay(AllBins), | 57 m_binDisplay(AllBins), |
346 switch (value) { | 346 switch (value) { |
347 default: | 347 default: |
348 case 0: return tr("Linear"); | 348 case 0: return tr("Linear"); |
349 case 1: return tr("Meter"); | 349 case 1: return tr("Meter"); |
350 case 2: return tr("dB"); | 350 case 2: return tr("dB"); |
351 case 3: return tr("Phase"); | 351 case 3: return tr("Other"); |
352 case 4: return tr("Phase"); | |
352 } | 353 } |
353 } | 354 } |
354 if (name == "Window Type") { | 355 if (name == "Window Type") { |
355 switch ((WindowType)value) { | 356 switch ((WindowType)value) { |
356 default: | 357 default: |
490 switch (value) { | 491 switch (value) { |
491 default: | 492 default: |
492 case 0: setColourScale(LinearColourScale); break; | 493 case 0: setColourScale(LinearColourScale); break; |
493 case 1: setColourScale(MeterColourScale); break; | 494 case 1: setColourScale(MeterColourScale); break; |
494 case 2: setColourScale(dBColourScale); break; | 495 case 2: setColourScale(dBColourScale); break; |
495 case 3: setColourScale(PhaseColourScale); break; | 496 case 3: setColourScale(OtherColourScale); break; |
497 case 4: setColourScale(PhaseColourScale); break; | |
496 } | 498 } |
497 } else if (name == "Frequency Scale") { | 499 } else if (name == "Frequency Scale") { |
498 switch (value) { | 500 switch (value) { |
499 default: | 501 default: |
500 case 0: setFrequencyScale(LinearFrequencyScale); break; | 502 case 0: setFrequencyScale(LinearFrequencyScale); break; |
680 SpectrogramLayer::setMinFrequency(size_t mf) | 682 SpectrogramLayer::setMinFrequency(size_t mf) |
681 { | 683 { |
682 if (m_minFrequency == mf) return; | 684 if (m_minFrequency == mf) return; |
683 | 685 |
684 invalidatePixmapCaches(); | 686 invalidatePixmapCaches(); |
687 invalidateMagnitudes(); | |
685 | 688 |
686 m_minFrequency = mf; | 689 m_minFrequency = mf; |
687 | 690 |
688 emit layerParametersChanged(); | 691 emit layerParametersChanged(); |
689 } | 692 } |
698 SpectrogramLayer::setMaxFrequency(size_t mf) | 701 SpectrogramLayer::setMaxFrequency(size_t mf) |
699 { | 702 { |
700 if (m_maxFrequency == mf) return; | 703 if (m_maxFrequency == mf) return; |
701 | 704 |
702 invalidatePixmapCaches(); | 705 invalidatePixmapCaches(); |
706 invalidateMagnitudes(); | |
703 | 707 |
704 m_maxFrequency = mf; | 708 m_maxFrequency = mf; |
705 | 709 |
706 emit layerParametersChanged(); | 710 emit layerParametersChanged(); |
707 } | 711 } |
804 SpectrogramLayer::setNormalizeColumns(bool n) | 808 SpectrogramLayer::setNormalizeColumns(bool n) |
805 { | 809 { |
806 if (m_normalizeColumns == n) return; | 810 if (m_normalizeColumns == n) return; |
807 | 811 |
808 invalidatePixmapCaches(); | 812 invalidatePixmapCaches(); |
813 invalidateMagnitudes(); | |
809 m_normalizeColumns = n; | 814 m_normalizeColumns = n; |
810 | 815 |
811 emit layerParametersChanged(); | 816 emit layerParametersChanged(); |
812 } | 817 } |
813 | 818 |
842 | 847 |
843 void | 848 void |
844 SpectrogramLayer::cacheInvalid() | 849 SpectrogramLayer::cacheInvalid() |
845 { | 850 { |
846 invalidatePixmapCaches(); | 851 invalidatePixmapCaches(); |
852 invalidateMagnitudes(); | |
847 } | 853 } |
848 | 854 |
849 void | 855 void |
850 SpectrogramLayer::cacheInvalid(size_t, size_t) | 856 SpectrogramLayer::cacheInvalid(size_t, size_t) |
851 { | 857 { |
1054 steadyState = false; | 1060 steadyState = false; |
1055 return frequency; | 1061 return frequency; |
1056 } | 1062 } |
1057 | 1063 |
1058 unsigned char | 1064 unsigned char |
1059 SpectrogramLayer::getDisplayValue(float input) const | 1065 SpectrogramLayer::getDisplayValue(View *v, float input) const |
1060 { | 1066 { |
1061 int value; | 1067 int value; |
1068 | |
1069 //!!! for the moment we're always normalizing visible area | |
1070 float min = m_viewMags[v].getMin(); | |
1071 float max = m_viewMags[v].getMax(); | |
1072 float thresh = -80.f; | |
1073 | |
1074 if (max == 0.f) max = 1.f; | |
1075 if (max == min) min = max - 0.0001f; | |
1062 | 1076 |
1063 switch (m_colourScale) { | 1077 switch (m_colourScale) { |
1064 | 1078 |
1065 default: | 1079 default: |
1066 case LinearColourScale: | 1080 case LinearColourScale: |
1067 value = int | 1081 // value = int |
1068 (input * (m_normalizeColumns ? 1.0 : 50.0) * 255.0) + 1; | 1082 // (input * (m_normalizeColumns ? 1.0 : 50.0) * 255.0) + 1; |
1083 value = int(((input - min) / (max - min)) * 255.f) + 1; | |
1069 break; | 1084 break; |
1070 | 1085 |
1071 case MeterColourScale: | 1086 case MeterColourScale: |
1072 value = AudioLevel::multiplier_to_preview | 1087 // value = AudioLevel::multiplier_to_preview |
1073 (input * (m_normalizeColumns ? 1.0 : 50.0), 255) + 1; | 1088 // (input * (m_normalizeColumns ? 1.0 : 50.0), 255) + 1; |
1089 value = AudioLevel::multiplier_to_preview((input - min) / (max - min), 255) + 1; | |
1074 break; | 1090 break; |
1075 | 1091 |
1076 case dBColourScale: | 1092 case dBColourScale: |
1077 input = 20.0 * log10(input); | 1093 //!!! experiment with normalizing the visible area this way. |
1078 input = (input + 80.0) / 80.0; | 1094 //In any case, we need to have some indication of what the dB |
1079 if (input < 0.0) input = 0.0; | 1095 //scale is relative to. |
1080 if (input > 1.0) input = 1.0; | 1096 input = 10.f * log10f(input / max); |
1081 value = int(input * 255.0) + 1; | 1097 if (min > 0.f) { |
1098 thresh = 10.f * log10f(min); | |
1099 if (thresh < -80.f) thresh = -80.f; | |
1100 } | |
1101 input = (input - thresh) / (-thresh); | |
1102 if (input < 0.f) input = 0.f; | |
1103 if (input > 1.f) input = 1.f; | |
1104 value = int(input * 255.f) + 1; | |
1105 break; | |
1106 | |
1107 case OtherColourScale: | |
1108 //!!! the "Other" scale is just where our current experiments go | |
1109 //!!! power rather than v | |
1110 input = 10.f * log10f((input * input) / (max * max)); | |
1111 if (min > 0.f) { | |
1112 thresh = 10.f * log10f(min * min); | |
1113 if (thresh < -80.f) thresh = -80.f; | |
1114 } | |
1115 input = (input - thresh) / (-thresh); | |
1116 if (input < 0.f) input = 0.f; | |
1117 if (input > 1.f) input = 1.f; | |
1118 value = int(input * 255.f) + 1; | |
1119 break; | |
1120 | |
1121 /*!!! | |
1122 input = 10.f * log10f(input * input); | |
1123 input = 1.f / (1.f + expf(- (input + 20.f) / 10.f)); | |
1124 | |
1125 if (input < 0.f) input = 0.f; | |
1126 if (input > 1.f) input = 1.f; | |
1127 value = int(input * 255.f) + 1; | |
1128 */ | |
1082 break; | 1129 break; |
1083 | 1130 |
1084 case PhaseColourScale: | 1131 case PhaseColourScale: |
1085 value = int((input * 127.0 / M_PI) + 128); | 1132 value = int((input * 127.0 / M_PI) + 128); |
1086 break; | 1133 break; |
1108 input = AudioLevel::preview_to_multiplier(value - 1, 255) | 1155 input = AudioLevel::preview_to_multiplier(value - 1, 255) |
1109 / (m_normalizeColumns ? 1.0 : 50.0); | 1156 / (m_normalizeColumns ? 1.0 : 50.0); |
1110 break; | 1157 break; |
1111 | 1158 |
1112 case dBColourScale: | 1159 case dBColourScale: |
1160 input = float(value - 1) / 255.0; | |
1161 input = (input * 80.0) - 80.0; | |
1162 input = powf(10.0, input) / 20.0; | |
1163 value = int(input); | |
1164 break; | |
1165 | |
1166 case OtherColourScale: | |
1113 input = float(value - 1) / 255.0; | 1167 input = float(value - 1) / 255.0; |
1114 input = (input * 80.0) - 80.0; | 1168 input = (input * 80.0) - 80.0; |
1115 input = powf(10.0, input) / 20.0; | 1169 input = powf(10.0, input) / 20.0; |
1116 value = int(input); | 1170 value = int(input); |
1117 break; | 1171 break; |
1471 i != m_fftAdapters.end(); ++i) { | 1525 i != m_fftAdapters.end(); ++i) { |
1472 delete i->second.first; | 1526 delete i->second.first; |
1473 } | 1527 } |
1474 | 1528 |
1475 m_fftAdapters.clear(); | 1529 m_fftAdapters.clear(); |
1530 } | |
1531 | |
1532 void | |
1533 SpectrogramLayer::invalidateMagnitudes() | |
1534 { | |
1535 m_viewMags.clear(); | |
1536 for (std::vector<MagnitudeRange>::iterator i = m_columnMags.begin(); | |
1537 i != m_columnMags.end(); ++i) { | |
1538 *i = MagnitudeRange(); | |
1539 } | |
1540 } | |
1541 | |
1542 bool | |
1543 SpectrogramLayer::updateViewMagnitudes(View *v) const | |
1544 { | |
1545 MagnitudeRange mag; | |
1546 | |
1547 int x0 = 0, x1 = v->width(); | |
1548 float s00 = 0, s01 = 0, s10 = 0, s11 = 0; | |
1549 | |
1550 getXBinRange(v, x0, s00, s01); | |
1551 getXBinRange(v, x1, s10, s11); | |
1552 | |
1553 int s0 = int(std::min(s00, s10) + 0.0001); | |
1554 int s1 = int(std::max(s01, s11)); | |
1555 | |
1556 if (m_columnMags.size() <= s1) { | |
1557 m_columnMags.resize(s1 + 1); | |
1558 } | |
1559 | |
1560 for (int s = s0; s <= s1; ++s) { | |
1561 if (m_columnMags[s].isSet()) { | |
1562 mag.sample(m_columnMags[s]); | |
1563 } | |
1564 } | |
1565 | |
1566 std::cerr << "SpectrogramLayer::updateViewMagnitudes returning from cols " | |
1567 << s0 << " -> " << s1 << " inclusive" << std::endl; | |
1568 | |
1569 if (!mag.isSet()) return false; | |
1570 if (mag == m_viewMags[v]) return false; | |
1571 m_viewMags[v] = mag; | |
1572 return true; | |
1476 } | 1573 } |
1477 | 1574 |
1478 void | 1575 void |
1479 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const | 1576 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const |
1480 { | 1577 { |
1657 */ | 1754 */ |
1658 | 1755 |
1659 if (recreateWholePixmapCache) { | 1756 if (recreateWholePixmapCache) { |
1660 x0 = 0; | 1757 x0 = 0; |
1661 x1 = v->width(); | 1758 x1 = v->width(); |
1759 } | |
1760 | |
1761 if (updateViewMagnitudes(v)) { | |
1762 std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | |
1763 } else { | |
1764 std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | |
1662 } | 1765 } |
1663 | 1766 |
1664 int paintBlockWidth = (300000 / zoomLevel); | 1767 int paintBlockWidth = (300000 / zoomLevel); |
1665 if (paintBlockWidth < 20) paintBlockWidth = 20; | 1768 if (paintBlockWidth < 20) paintBlockWidth = 20; |
1666 | 1769 |
1748 for (size_t q = minbin; q <= bins; ++q) { | 1851 for (size_t q = minbin; q <= bins; ++q) { |
1749 float f0 = (float(q) * sr) / fftSize; | 1852 float f0 = (float(q) * sr) / fftSize; |
1750 yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic); | 1853 yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic); |
1751 } | 1854 } |
1752 | 1855 |
1856 MagnitudeRange overallMag = m_viewMags[v]; | |
1857 bool overallMagChanged = false; | |
1858 | |
1753 for (int x = 0; x < w; ++x) { | 1859 for (int x = 0; x < w; ++x) { |
1754 | 1860 |
1755 for (int y = 0; y < h; ++y) { | 1861 for (int y = 0; y < h; ++y) { |
1756 ymag[y] = 0.0; | 1862 ymag[y] = 0.0; |
1757 ydiv[y] = 0.0; | 1863 ydiv[y] = 0.0; |
1776 } | 1882 } |
1777 | 1883 |
1778 for (int s = s0i; s <= s1i; ++s) { | 1884 for (int s = s0i; s <= s1i; ++s) { |
1779 | 1885 |
1780 if (!fft->isColumnReady(s)) continue; | 1886 if (!fft->isColumnReady(s)) continue; |
1887 MagnitudeRange mag; | |
1781 | 1888 |
1782 for (size_t q = minbin; q < bins; ++q) { | 1889 for (size_t q = minbin; q < bins; ++q) { |
1783 | 1890 |
1784 float y0 = yval[q + 1]; | 1891 float y0 = yval[q + 1]; |
1785 float y1 = yval[q]; | 1892 float y1 = yval[q]; |
1820 float value; | 1927 float value; |
1821 | 1928 |
1822 if (m_colourScale == PhaseColourScale) { | 1929 if (m_colourScale == PhaseColourScale) { |
1823 value = fft->getPhaseAt(s, q); | 1930 value = fft->getPhaseAt(s, q); |
1824 } else if (m_normalizeColumns) { | 1931 } else if (m_normalizeColumns) { |
1825 value = fft->getNormalizedMagnitudeAt(s, q) * m_gain; | 1932 value = fft->getNormalizedMagnitudeAt(s, q); |
1933 mag.sample(value); | |
1934 value *= m_gain; | |
1826 } else { | 1935 } else { |
1827 value = fft->getMagnitudeAt(s, q) * m_gain; | 1936 value = fft->getMagnitudeAt(s, q); |
1937 mag.sample(value); | |
1938 value *= m_gain; | |
1828 } | 1939 } |
1829 | 1940 |
1830 for (int y = y0i; y <= y1i; ++y) { | 1941 for (int y = y0i; y <= y1i; ++y) { |
1831 | 1942 |
1832 if (y < 0 || y >= h) continue; | 1943 if (y < 0 || y >= h) continue; |
1836 if (y == y1i) yprop *= y1 - y; | 1947 if (y == y1i) yprop *= y1 - y; |
1837 ymag[y] += yprop * value; | 1948 ymag[y] += yprop * value; |
1838 ydiv[y] += yprop; | 1949 ydiv[y] += yprop; |
1839 } | 1950 } |
1840 } | 1951 } |
1952 | |
1953 if (mag.isSet()) { | |
1954 | |
1955 m_columnMags[s].sample(mag); | |
1956 | |
1957 if (overallMag.sample(mag)) { | |
1958 //!!! scaling would change here | |
1959 overallMagChanged = true; | |
1960 std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl; | |
1961 } | |
1962 } | |
1841 } | 1963 } |
1842 | 1964 |
1843 for (int y = 0; y < h; ++y) { | 1965 for (int y = 0; y < h; ++y) { |
1844 | 1966 |
1845 if (ydiv[y] > 0.0) { | 1967 if (ydiv[y] > 0.0) { |
1846 | 1968 |
1847 unsigned char pixel = 0; | 1969 unsigned char pixel = 0; |
1848 | 1970 |
1849 float avg = ymag[y] / ydiv[y]; | 1971 float avg = ymag[y] / ydiv[y]; |
1850 pixel = getDisplayValue(avg); | 1972 pixel = getDisplayValue(v, avg); |
1851 | 1973 |
1852 assert(x <= m_drawBuffer.width()); | 1974 assert(x <= m_drawBuffer.width()); |
1853 QColor c = m_colourMap.getColour(pixel); | 1975 QColor c = m_colourMap.getColour(pixel); |
1854 m_drawBuffer.setPixel(x, y, | 1976 m_drawBuffer.setPixel(x, y, |
1855 qRgb(c.red(), c.green(), c.blue())); | 1977 qRgb(c.red(), c.green(), c.blue())); |
1856 } | 1978 } |
1857 } | 1979 } |
1858 } | 1980 } |
1859 | 1981 |
1982 if (overallMagChanged) { | |
1983 m_viewMags[v] = overallMag; | |
1984 std::cerr << "Overall mag is now [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "] - will be updating" << std::endl; | |
1985 } else { | |
1986 std::cerr << "Overall mag unchanged at [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | |
1987 } | |
1988 | |
1860 paint.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); | 1989 paint.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); |
1861 | 1990 |
1862 if (recreateWholePixmapCache) { | 1991 if (recreateWholePixmapCache) { |
1863 cache.pixmap = QPixmap(v->width(), v->height()); | 1992 cache.pixmap = QPixmap(v->width(), v->height()); |
1864 } | 1993 } |
1865 | 1994 |
1866 QPainter cachePainter(&cache.pixmap); | 1995 QPainter cachePainter(&cache.pixmap); |
1867 cachePainter.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); | 1996 cachePainter.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h); |
1868 cachePainter.end(); | 1997 cachePainter.end(); |
1869 | 1998 |
1870 cache.startFrame = startFrame; | 1999 if (!overallMagChanged) { |
1871 cache.zoomLevel = zoomLevel; | 2000 |
1872 | 2001 cache.startFrame = startFrame; |
1873 if (cache.validArea.x() > 0) { | 2002 cache.zoomLevel = zoomLevel; |
2003 | |
2004 if (cache.validArea.x() > 0) { | |
1874 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2005 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1875 std::cerr << "SpectrogramLayer::paint() updating left" << std::endl; | 2006 std::cerr << "SpectrogramLayer::paint() updating left" << std::endl; |
1876 #endif | 2007 #endif |
1877 v->update(0, 0, cache.validArea.x(), v->height()); | 2008 v->update(0, 0, cache.validArea.x(), v->height()); |
1878 } | 2009 } |
1879 | 2010 |
1880 if (cache.validArea.x() + cache.validArea.width() < | 2011 if (cache.validArea.x() + cache.validArea.width() < |
1881 cache.pixmap.width()) { | 2012 cache.pixmap.width()) { |
1882 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2013 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1883 std::cerr << "SpectrogramLayer::paint() updating right (" | 2014 std::cerr << "SpectrogramLayer::paint() updating right (" |
1884 << cache.validArea.x() + cache.validArea.width() | 2015 << cache.validArea.x() + cache.validArea.width() |
1885 << ", " | 2016 << ", " |
1886 << cache.pixmap.width() - (cache.validArea.x() + | 2017 << cache.pixmap.width() - (cache.validArea.x() + |
1887 cache.validArea.width()) | 2018 cache.validArea.width()) |
1888 << ")" << std::endl; | 2019 << ")" << std::endl; |
1889 #endif | 2020 #endif |
1890 v->update(cache.validArea.x() + cache.validArea.width(), | 2021 v->update(cache.validArea.x() + cache.validArea.width(), |
1891 0, | 2022 0, |
1892 cache.pixmap.width() - (cache.validArea.x() + | 2023 cache.pixmap.width() - (cache.validArea.x() + |
1893 cache.validArea.width()), | 2024 cache.validArea.width()), |
1894 v->height()); | 2025 v->height()); |
2026 } | |
2027 } else { | |
2028 // overallMagChanged | |
2029 cache.validArea = QRect(); | |
2030 v->update(); | |
1895 } | 2031 } |
1896 | 2032 |
1897 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2033 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1898 std::cerr << "SpectrogramLayer::paint() returning" << std::endl; | 2034 std::cerr << "SpectrogramLayer::paint() returning" << std::endl; |
1899 #endif | 2035 #endif |
2138 int | 2274 int |
2139 SpectrogramLayer::getColourScaleWidth(QPainter &paint) const | 2275 SpectrogramLayer::getColourScaleWidth(QPainter &paint) const |
2140 { | 2276 { |
2141 int cw; | 2277 int cw; |
2142 | 2278 |
2279 cw = paint.fontMetrics().width("-80dB"); | |
2280 | |
2281 /*!!! | |
2143 switch (m_colourScale) { | 2282 switch (m_colourScale) { |
2144 default: | 2283 default: |
2145 case LinearColourScale: | 2284 case LinearColourScale: |
2146 cw = paint.fontMetrics().width(QString("0.00")); | 2285 cw = paint.fontMetrics().width(QString("0.00")); |
2147 break; | 2286 break; |
2148 | 2287 |
2149 case MeterColourScale: | 2288 case MeterColourScale: |
2150 case dBColourScale: | 2289 case dBColourScale: |
2290 case OtherColourScale: | |
2151 cw = std::max(paint.fontMetrics().width(tr("-Inf")), | 2291 cw = std::max(paint.fontMetrics().width(tr("-Inf")), |
2152 paint.fontMetrics().width(tr("-90"))); | 2292 paint.fontMetrics().width(tr("-90"))); |
2153 break; | 2293 break; |
2154 | 2294 |
2155 case PhaseColourScale: | 2295 case PhaseColourScale: |
2156 cw = paint.fontMetrics().width(QString("-") + QChar(0x3c0)); | 2296 cw = paint.fontMetrics().width(QString("-") + QChar(0x3c0)); |
2157 break; | 2297 break; |
2158 } | 2298 } |
2299 */ | |
2300 | |
2159 | 2301 |
2160 return cw; | 2302 return cw; |
2161 } | 2303 } |
2162 | 2304 |
2163 int | 2305 int |
2199 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); | 2341 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); |
2200 if (bins > m_fftSize / 2) bins = m_fftSize / 2; | 2342 if (bins > m_fftSize / 2) bins = m_fftSize / 2; |
2201 } | 2343 } |
2202 | 2344 |
2203 int cw = getColourScaleWidth(paint); | 2345 int cw = getColourScaleWidth(paint); |
2346 int cbw = paint.fontMetrics().width("dB"); | |
2204 | 2347 |
2205 int py = -1; | 2348 int py = -1; |
2206 int textHeight = paint.fontMetrics().height(); | 2349 int textHeight = paint.fontMetrics().height(); |
2207 int toff = -textHeight + paint.fontMetrics().ascent() + 2; | 2350 int toff = -textHeight + paint.fontMetrics().ascent() + 2; |
2208 | 2351 |
2209 if (h > textHeight * 2 + 10) { | 2352 if (h > textHeight * 3 + 10) { |
2210 | 2353 |
2211 int ch = h - textHeight * 2 - 8; | 2354 int topLines = 2; |
2212 paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); | 2355 if (m_colourScale == PhaseColourScale) topLines = 1; |
2356 | |
2357 int ch = h - textHeight * (topLines + 1) - 8; | |
2358 // paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); | |
2359 paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1); | |
2213 | 2360 |
2214 QString top, bottom; | 2361 QString top, bottom; |
2215 | 2362 /*!!! |
2216 switch (m_colourScale) { | 2363 switch (m_colourScale) { |
2217 default: | 2364 default: |
2218 case LinearColourScale: | 2365 case LinearColourScale: |
2219 top = (m_normalizeColumns ? "1.0" : "0.02"); | 2366 top = (m_normalizeColumns ? "1.0" : "0.02"); |
2220 bottom = (m_normalizeColumns ? "0.0" : "0.00"); | 2367 bottom = (m_normalizeColumns ? "0.0" : "0.00"); |
2227 arg(int(AudioLevel::multiplier_to_dB | 2374 arg(int(AudioLevel::multiplier_to_dB |
2228 (AudioLevel::preview_to_multiplier(0, 255)))); | 2375 (AudioLevel::preview_to_multiplier(0, 255)))); |
2229 break; | 2376 break; |
2230 | 2377 |
2231 case dBColourScale: | 2378 case dBColourScale: |
2379 case OtherColourScale: | |
2232 top = "0"; | 2380 top = "0"; |
2233 bottom = "-80"; | 2381 bottom = "-80"; |
2234 break; | 2382 break; |
2235 | 2383 |
2236 case PhaseColourScale: | 2384 case PhaseColourScale: |
2237 top = QChar(0x3c0); | 2385 top = QChar(0x3c0); |
2238 bottom = "-" + top; | 2386 bottom = "-" + top; |
2239 break; | 2387 break; |
2240 } | 2388 } |
2241 | 2389 */ |
2242 paint.drawText((cw + 6 - paint.fontMetrics().width(top)) / 2, | 2390 float min = m_viewMags[v].getMin(); |
2243 2 + textHeight + toff, top); | 2391 float max = m_viewMags[v].getMax(); |
2244 | 2392 |
2245 paint.drawText((cw + 6 - paint.fontMetrics().width(bottom)) / 2, | 2393 float dBmin = AudioLevel::multiplier_to_dB(min); |
2246 h + toff - 3, bottom); | 2394 float dBmax = AudioLevel::multiplier_to_dB(max); |
2395 | |
2396 if (dBmin < -80.f) dBmin = -80.f; | |
2397 bottom = QString("%1").arg(lrintf(dBmin)); | |
2398 | |
2399 if (dBmax < -80.f) dBmax = -80.f; | |
2400 else top = QString("%1").arg(lrintf(dBmax)); | |
2401 | |
2402 //!!! & phase etc | |
2403 | |
2404 if (m_colourScale != PhaseColourScale) { | |
2405 paint.drawText((cw + 6 - paint.fontMetrics().width("dBFS")) / 2, | |
2406 2 + textHeight + toff, "dBFS"); | |
2407 } | |
2408 | |
2409 // paint.drawText((cw + 6 - paint.fontMetrics().width(top)) / 2, | |
2410 paint.drawText(3 + cw - cbw - paint.fontMetrics().width(top), | |
2411 2 + textHeight * topLines + toff + textHeight/2, top); | |
2412 | |
2413 paint.drawText(3 + cw - cbw - paint.fontMetrics().width(bottom), | |
2414 h + toff - 3 - textHeight/2, bottom); | |
2247 | 2415 |
2248 paint.save(); | 2416 paint.save(); |
2249 paint.setBrush(Qt::NoBrush); | 2417 paint.setBrush(Qt::NoBrush); |
2418 | |
2419 int lasty = 0; | |
2420 int lastdb = 0; | |
2421 | |
2250 for (int i = 0; i < ch; ++i) { | 2422 for (int i = 0; i < ch; ++i) { |
2251 int v = (i * 255) / ch + 1; | 2423 |
2252 paint.setPen(m_colourMap.getColour(v)); | 2424 float dBval = dBmin + (((dBmax - dBmin) * i) / (ch - 1)); |
2253 paint.drawLine(5, 4 + textHeight + ch - i, | 2425 int idb = int(dBval); |
2254 cw + 2, 4 + textHeight + ch - i); | 2426 |
2427 float value = AudioLevel::dB_to_multiplier(dBval); | |
2428 int colour = getDisplayValue(v, value * m_gain); | |
2429 /* | |
2430 float value = min + (((max - min) * i) / (ch - 1)); | |
2431 if (value < m_threshold) value = 0.f; | |
2432 int colour = getDisplayValue(v, value * m_gain); | |
2433 */ | |
2434 /* | |
2435 int colour = (i * 255) / ch + 1; | |
2436 */ | |
2437 paint.setPen(m_colourMap.getColour(colour)); | |
2438 | |
2439 int y = textHeight * topLines + 4 + ch - i; | |
2440 | |
2441 paint.drawLine(5 + cw - cbw, y, cw + 2, y); | |
2442 | |
2443 // paint.drawLine(5, 4 + textHeight + ch - i, | |
2444 // cw + 2, 4 + textHeight + ch - i); | |
2445 | |
2446 | |
2447 if (i == 0) { | |
2448 lasty = y; | |
2449 lastdb = idb; | |
2450 } else if (i < ch - paint.fontMetrics().ascent() && | |
2451 ((abs(y - lasty) > textHeight && | |
2452 idb % 10 == 0) || | |
2453 (abs(y - lasty) > paint.fontMetrics().ascent() && | |
2454 idb % 5 == 0))) { | |
2455 paint.setPen(Qt::black); | |
2456 QString text = QString("%1").arg(idb); | |
2457 paint.drawText(3 + cw - cbw - paint.fontMetrics().width(text), | |
2458 y + toff + textHeight/2, text); | |
2459 paint.setPen(Qt::white); | |
2460 paint.drawLine(5 + cw - cbw, y, 8 + cw - cbw, y); | |
2461 lasty = y; | |
2462 lastdb = idb; | |
2463 } | |
2255 } | 2464 } |
2256 paint.restore(); | 2465 paint.restore(); |
2257 } | 2466 } |
2258 | 2467 |
2259 paint.drawLine(cw + 7, 0, cw + 7, h); | 2468 paint.drawLine(cw + 7, 0, cw + 7, h); |