Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 332:6440e280122e spectrogram-cache-rejig
* Some bits and bobs of cache mangling -- closer to working, but still not
author | Chris Cannam |
---|---|
date | Mon, 19 Nov 2007 15:50:37 +0000 |
parents | 846746e4e865 |
children | 64e84e5efb76 |
comparison
equal
deleted
inserted
replaced
330:846746e4e865 | 332:6440e280122e |
---|---|
1754 | 1754 |
1755 QMutexLocker locker(&m_pixmapCacheMutex); | 1755 QMutexLocker locker(&m_pixmapCacheMutex); |
1756 | 1756 |
1757 rect = v->rect(); //!!! | 1757 rect = v->rect(); //!!! |
1758 | 1758 |
1759 float ratio = float(v->getZoomLevel()) / float(getWindowIncrement()); | |
1760 int imageWidth = lrintf(v->width() * ratio); | |
1761 | |
1759 PixmapCache *cache = m_pixmapCaches[v]; | 1762 PixmapCache *cache = m_pixmapCaches[v]; |
1760 if (!cache) { | 1763 if (!cache) { |
1761 cache = new PixmapCache; | 1764 cache = new PixmapCache; |
1762 cache->pixmap = 0; | 1765 cache->pixmap = 0; |
1763 m_pixmapCaches[v] = cache; | 1766 m_pixmapCaches[v] = cache; |
1764 cache->mutex.lock(); | 1767 cache->mutex.lock(); |
1765 cache->pixmap = new QImage(v->width(), v->height(), | 1768 cache->pixmap = new QImage(imageWidth, v->height(), |
1766 QImage::Format_RGB32); | 1769 QImage::Format_RGB32); |
1767 cache->mutex.unlock(); | 1770 cache->mutex.unlock(); |
1768 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1771 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1769 std::cerr << "SpectrogramLayer::paint: Created new cache, size " | 1772 std::cerr << "SpectrogramLayer::paint: Created new cache, size " |
1770 << v->width() << "x" << v->height() << " (" | 1773 << v->width() << "x" << v->height() << " (" |
1771 << v->width() * v->height() * 4 << " bytes)" << std::endl; | 1774 << v->width() * v->height() * 4 << " bytes)" << std::endl; |
1772 #endif | 1775 #endif |
1773 return; //!!! prod paint thread | 1776 return; //!!! prod paint thread |
1774 } | 1777 } |
1775 | 1778 |
1776 if (!cache->mutex.tryLock()) { | |
1777 std::cerr << "lock unavailable" << std::endl; | |
1778 paint.drawImage(rect,// & cache->validArea, | |
1779 *cache->pixmap, | |
1780 rect);// & cache->validArea); | |
1781 // v->update(rect); | |
1782 return; | |
1783 } | |
1784 | |
1785 if (cache->pixmap->width() != v->width() || | |
1786 cache->pixmap->height() != v->height()) { | |
1787 QImage *newImage = new QImage | |
1788 (cache->pixmap->scaled(v->width(), v->height())); | |
1789 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1790 std::cerr << "SpectrogramLayer::paint: Rescaling cache to size " | |
1791 << v->width() << "x" << v->height() << " (" | |
1792 << v->width() * v->height() * 4 << " bytes)" << std::endl; | |
1793 #endif | |
1794 delete cache->pixmap; | |
1795 cache->pixmap = newImage; | |
1796 } | |
1797 | |
1798 // The cache has the correct resolution for the view in the y | |
1799 // axis, but with a resolution of one pixel per increment in the x | |
1800 // axis. We may need to rescale when drawing. | |
1801 | |
1802 paint.setRenderHint(QPainter::SmoothPixmapTransform, true); | |
1803 | |
1804 //!!! not quite right in any case except integer ratio -- either | |
1805 //source or target rect will have edges at non-integral | |
1806 //coordinates | |
1807 | |
1808 float ratio = float(v->getZoomLevel()) / float(getWindowIncrement()); | |
1809 | |
1810 long myStartFrame = v->getStartFrame(); | 1779 long myStartFrame = v->getStartFrame(); |
1811 long cacheStartFrame = cache->startFrame; | 1780 long cacheStartFrame = cache->startFrame; |
1812 long xoff = (myStartFrame - cacheStartFrame) / getWindowIncrement(); | 1781 long xoff = (myStartFrame - cacheStartFrame) / getWindowIncrement(); |
1813 | |
1814 std::cerr << "my start frame = " << myStartFrame << ", cache start frame = " << cacheStartFrame << std::endl; | |
1815 | 1782 |
1816 QRect sourceRect = QRect(lrintf(rect.x() * ratio) + xoff, | 1783 QRect sourceRect = QRect(lrintf(rect.x() * ratio) + xoff, |
1817 rect.y(), | 1784 rect.y(), |
1818 lrintf(rect.width() * ratio), | 1785 lrintf(rect.width() * ratio), |
1819 rect.height()); | 1786 rect.height()); |
1787 | |
1788 if (!cache->mutex.tryLock()) { | |
1789 std::cerr << "lock unavailable" << std::endl; | |
1790 | |
1791 paint.drawImage(rect, | |
1792 cache->pixmap->copy(sourceRect) | |
1793 .scaled(rect.size(), | |
1794 Qt::IgnoreAspectRatio, | |
1795 Qt::SmoothTransformation)); | |
1796 | |
1797 // paint.drawImage(rect,// & cache->validArea, | |
1798 // *cache->pixmap, | |
1799 // rect);// & cache->validArea); | |
1800 // v->update(rect); | |
1801 return; | |
1802 } | |
1803 | |
1804 if (cache->pixmap->width() != imageWidth || | |
1805 cache->pixmap->height() != v->height()) { | |
1806 QImage *newImage = new QImage | |
1807 (cache->pixmap->scaled(imageWidth, v->height(), | |
1808 Qt::IgnoreAspectRatio, | |
1809 Qt::SmoothTransformation)); | |
1810 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
1811 std::cerr << "SpectrogramLayer::paint: Rescaling cache to size " | |
1812 << imageWidth << "x" << v->height() << " (" | |
1813 << imageWidth * v->height() * 4 << " bytes)" << std::endl; | |
1814 #endif | |
1815 delete cache->pixmap; | |
1816 cache->pixmap = newImage; | |
1817 } | |
1818 | |
1819 // The cache has the correct resolution for the view in the y | |
1820 // axis, but with a resolution of one pixel per increment in the x | |
1821 // axis. We may need to rescale when drawing. | |
1822 | |
1823 paint.setRenderHint(QPainter::SmoothPixmapTransform, true); | |
1824 | |
1825 //!!! not quite right in any case except integer ratio -- either | |
1826 //source or target rect will have edges at non-integral | |
1827 //coordinates | |
1828 | |
1829 std::cerr << "my start frame = " << myStartFrame << ", cache start frame = " << cacheStartFrame << std::endl; | |
1820 | 1830 |
1821 std::cerr << "ratio = " << ratio << " (zoom " << v->getZoomLevel() | 1831 std::cerr << "ratio = " << ratio << " (zoom " << v->getZoomLevel() |
1822 << ", incr " << getWindowIncrement() << "); source rect " | 1832 << ", incr " << getWindowIncrement() << "); source rect " |
1823 << sourceRect.x() << "," << sourceRect.y() | 1833 << sourceRect.x() << "," << sourceRect.y() |
1824 << " " << sourceRect.width() << "x" << sourceRect.height() | 1834 << " " << sourceRect.width() << "x" << sourceRect.height() |
1828 << " (image " << cache->pixmap->width() << "x" | 1838 << " (image " << cache->pixmap->width() << "x" |
1829 << cache->pixmap->height() << ")" | 1839 << cache->pixmap->height() << ")" |
1830 << std::endl; | 1840 << std::endl; |
1831 | 1841 |
1832 paint.drawImage(rect,// & cache->validArea, | 1842 paint.drawImage(rect,// & cache->validArea, |
1833 *cache->pixmap, | 1843 cache->pixmap->copy(sourceRect) |
1834 sourceRect);// & cache->validArea); | 1844 .scaled(rect.size(), |
1845 Qt::IgnoreAspectRatio, | |
1846 Qt::SmoothTransformation)); | |
1847 // *cache->pixmap, | |
1848 // sourceRect);// & cache->validArea); | |
1835 | 1849 |
1836 if (cache->startFrame != v->getStartFrame()) { | 1850 if (cache->startFrame != v->getStartFrame()) { |
1837 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1851 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1838 std::cerr << "SpectrogramLayer::paint(): Cache start frame " | 1852 std::cerr << "SpectrogramLayer::paint(): Cache start frame " |
1839 << cache->startFrame << " differs from view start frame " | 1853 << cache->startFrame << " differs from view start frame " |
1891 if (m_exiting) break; | 1905 if (m_exiting) break; |
1892 } | 1906 } |
1893 | 1907 |
1894 if (!m_exiting) { | 1908 if (!m_exiting) { |
1895 //!!! wait on condition | 1909 //!!! wait on condition |
1896 if (workToDo) usleep(100); | 1910 if (workToDo) ; // usleep(100); |
1897 else sleep(1); | 1911 else sleep(1); |
1898 } | 1912 } |
1899 } | 1913 } |
1900 } | 1914 } |
1901 | 1915 |
2005 bool recreateWholeCache = true; | 2019 bool recreateWholeCache = true; |
2006 | 2020 |
2007 int x0 = rect.left(); | 2021 int x0 = rect.left(); |
2008 int x1 = rect.right() + 1; | 2022 int x1 = rect.right() + 1; |
2009 | 2023 |
2010 if (cache.validArea.width() > 0) { | |
2011 | |
2012 //!!! no, the gui thread will handle resizes -- we just draw | |
2013 //the area that's available in the cache. If the image is | |
2014 //enlarged, our valid area should remain the same and we'll | |
2015 //pick up on the discrepancy naturally (we hope) | |
2016 // if (cache.pixmap->width() == v->width() && | |
2017 // cache.pixmap->height() == v->height()) { | |
2018 | |
2019 if (cache.startFrame / increment == startFrame / increment && | |
2020 cache.validArea.x() <= x0 && | |
2021 cache.validArea.x() + cache.validArea.width() >= x1) { | |
2022 | |
2023 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2024 std::cerr << "SpectrogramLayer: pixmap cache good" << std::endl; | |
2025 #endif | |
2026 | |
2027 //!!! set a flag to that effect? | |
2028 | |
2029 return true; | |
2030 | |
2031 } else { | |
2032 | |
2033 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2034 std::cerr << "SpectrogramLayer: pixmap cache partially OK" << std::endl; | |
2035 #endif | |
2036 | |
2037 recreateWholeCache = false; | |
2038 | |
2039 int dx = cache.startFrame / increment - startFrame / increment; | |
2040 | |
2041 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2042 std::cerr << "SpectrogramLayer: dx = " << dx << " (pixmap cache " << cache.pixmap->width() << "x" << cache.pixmap->height() << ")" << std::endl; | |
2043 #endif | |
2044 | |
2045 if (dx != 0 && dx > -w && dx < w) { | |
2046 | |
2047 #if defined(Q_WS_WIN32) || defined(Q_WS_MAC) | |
2048 // Copying a pixmap to itself doesn't work | |
2049 // properly on Windows or Mac (it only works when | |
2050 // moving in one direction). | |
2051 | |
2052 //!!! Need a utility function for this | |
2053 | |
2054 //!!! test again on Win and OS/X for images (above | |
2055 //comment applies to pixmaps) | |
2056 | |
2057 //!!! indeed, test again on linux for images too | |
2058 //-- I bet it doesn't work | |
2059 | |
2060 static QImage *tmpPixmap = 0; | |
2061 if (!tmpPixmap || | |
2062 tmpPixmap->width() != cache.pixmap->width() || | |
2063 tmpPixmap->height() != cache.pixmap->height()) { | |
2064 delete tmpPixmap; | |
2065 tmpPixmap = new QImage(cache.pixmap->width(), | |
2066 cache.pixmap->height(), | |
2067 QImage::Format_RGB32); | |
2068 } | |
2069 QPainter tmpPainter; | |
2070 tmpPainter.begin(tmpPixmap); | |
2071 tmpPainter.drawImage(0, 0, image); | |
2072 tmpPainter.end(); | |
2073 paint.drawImage(dx, 0, *tmpPixmap); | |
2074 #else | |
2075 paint.drawImage(dx, 0, image); //!!! see above | |
2076 #endif | |
2077 | |
2078 int px = cache.validArea.x(); | |
2079 int pw = cache.validArea.width(); | |
2080 | |
2081 if (dx < 0) { | |
2082 x0 = w + dx; | |
2083 x1 = w; | |
2084 px += dx; | |
2085 if (px < 0) { | |
2086 pw += px; | |
2087 px = 0; | |
2088 if (pw < 0) pw = 0; | |
2089 } | |
2090 } else { | |
2091 x0 = 0; | |
2092 x1 = dx; | |
2093 px += dx; | |
2094 if (px + pw > w) { | |
2095 pw = int(w) - px; | |
2096 if (pw < 0) pw = 0; | |
2097 } | |
2098 } | |
2099 | |
2100 cache.validArea = | |
2101 QRect(px, cache.validArea.y(), | |
2102 pw, cache.validArea.height()); | |
2103 } | |
2104 } | |
2105 // } else { | |
2106 //#ifdef DEBUG_SPECTROGRAM_REPAINT | |
2107 // std::cerr << "SpectrogramLayer: pixmap cache useless" << std::endl; | |
2108 // if (cache.pixmap->width() != v->width()) { | |
2109 // std::cerr << "(cache width " << cache.pixmap->width() | |
2110 // << " != " << v->width(); | |
2111 // } | |
2112 // if (cache.pixmap->height() != v->height()) { | |
2113 // std::cerr << "(cache height " << cache.pixmap->height() | |
2114 // << " != " << v->height(); | |
2115 // } | |
2116 //#endif | |
2117 // cache.validArea = QRect(); | |
2118 // } | |
2119 } | |
2120 | |
2121 /*!!! | |
2122 if (updateViewMagnitudes(v)) { | |
2123 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2124 std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | |
2125 #endif | |
2126 recreateWholeCache = true; | |
2127 } else { | |
2128 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2129 std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | |
2130 #endif | |
2131 } | |
2132 */ | |
2133 if (recreateWholeCache) { | |
2134 x0 = 0; | |
2135 x1 = w; | |
2136 } | |
2137 | |
2138 struct timeval tv; | 2024 struct timeval tv; |
2139 (void)gettimeofday(&tv, 0); | 2025 (void)gettimeofday(&tv, 0); |
2140 RealTime mainPaintStart = RealTime::fromTimeval(tv); | 2026 RealTime mainPaintStart = RealTime::fromTimeval(tv); |
2141 | 2027 |
2142 int paintBlockWidth = m_lastPaintBlockWidth; | 2028 int paintBlockWidth = m_lastPaintBlockWidth; |
2161 | 2047 |
2162 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2048 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2163 std::cerr << "[" << this << "]: last paint width: " << m_lastPaintBlockWidth << ", last paint time: " << m_lastPaintTime << ", new paint width: " << paintBlockWidth << std::endl; | 2049 std::cerr << "[" << this << "]: last paint width: " << m_lastPaintBlockWidth << ", last paint time: " << m_lastPaintTime << ", new paint width: " << paintBlockWidth << std::endl; |
2164 #endif | 2050 #endif |
2165 | 2051 |
2052 recreateWholeCache = checkAndScrollCache(cache, paint, | |
2053 startFrame, increment, | |
2054 x0, x1); | |
2055 | |
2056 selectPaintStrip(cache, x0, x1, paintBlockWidth); | |
2057 | |
2166 // We always paint the full height when refreshing the cache. | 2058 // We always paint the full height when refreshing the cache. |
2167 // Smaller heights can be used when painting from cache, but we | 2059 // Smaller heights can be used when painting from cache, but we |
2168 // want to ensure the cache is coherent without having to worry | 2060 // want to ensure the cache is coherent without having to worry |
2169 // about vertical matching of required and valid areas as well as | 2061 // about vertical matching of required and valid areas as well as |
2170 // horizontal. | 2062 // horizontal. |
2242 interpolate = true; | 2134 interpolate = true; |
2243 } | 2135 } |
2244 } | 2136 } |
2245 | 2137 |
2246 bool runOutOfData = false; | 2138 bool runOutOfData = false; |
2139 | |
2140 std::cerr << "painting from " << x0 << " to " << x1 << std::endl; | |
2247 | 2141 |
2248 for (int x = 0; x < (x1 - x0); ++x) { | 2142 for (int x = 0; x < (x1 - x0); ++x) { |
2249 | 2143 |
2250 if (runOutOfData) break; | 2144 if (runOutOfData) break; |
2251 | 2145 |
2454 std::cerr << "Overall mag unchanged at [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | 2348 std::cerr << "Overall mag unchanged at [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; |
2455 #endif | 2349 #endif |
2456 } | 2350 } |
2457 */ | 2351 */ |
2458 if (cache.validArea.width() > 0) { | 2352 if (cache.validArea.width() > 0) { |
2459 | 2353 |
2460 int vx0 = 0, vx1 = 0; | 2354 int vx0 = 0, vx1 = 0; |
2461 vx0 = cache.validArea.x(); | 2355 vx0 = cache.validArea.x(); |
2462 vx1 = cache.validArea.x() + cache.validArea.width(); | 2356 vx1 = cache.validArea.x() + cache.validArea.width(); |
2463 | 2357 |
2464 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2465 std::cerr << "x0 " << x0 << ", x1 " << x1 << ", vx0 " << vx0 << ", vx1 " << vx1 << ", paintBlockWidth " << paintBlockWidth << std::endl; | |
2466 #endif | |
2467 if (x0 < vx0) { | |
2468 if (x0 + paintBlockWidth < vx0) { | |
2469 x0 = vx0 - paintBlockWidth; | |
2470 } else { | |
2471 x0 = 0; | |
2472 } | |
2473 } else if (x0 > vx1) { | |
2474 x0 = vx1; | |
2475 } | |
2476 | |
2477 if (x1 < vx0) { | |
2478 x1 = vx0; | |
2479 } else if (x1 > vx1) { | |
2480 if (vx1 + paintBlockWidth < x1) { | |
2481 x1 = vx1 + paintBlockWidth; | |
2482 } else { | |
2483 x1 = v->width(); | |
2484 } | |
2485 } | |
2486 | |
2487 cache.validArea = QRect | 2358 cache.validArea = QRect |
2488 (std::min(vx0, x0), cache.validArea.y(), | 2359 (std::min(vx0, x0), cache.validArea.y(), |
2489 std::max(vx1 - std::min(vx0, x0), | 2360 std::max(vx1 - std::min(vx0, x0), |
2490 x1 - std::min(vx0, x0)), | 2361 x1 - std::min(vx0, x0)), |
2491 cache.validArea.height()); | 2362 cache.validArea.height()); |
2492 | 2363 |
2493 } else { | 2364 } else { |
2494 if (x1 > x0 + paintBlockWidth) { | 2365 |
2495 int sfx = x1; | |
2496 if (startFrame < 0) sfx = v->getXForFrame(0); //!!! | |
2497 if (sfx >= x0 && sfx + paintBlockWidth <= x1) { | |
2498 x0 = sfx; | |
2499 x1 = x0 + paintBlockWidth; | |
2500 } else { | |
2501 int mid = (x1 + x0) / 2; | |
2502 x0 = mid - paintBlockWidth/2; | |
2503 x1 = x0 + paintBlockWidth; | |
2504 } | |
2505 } | |
2506 cache.validArea = QRect(x0, 0, x1 - x0, h); | 2366 cache.validArea = QRect(x0, 0, x1 - x0, h); |
2507 } | 2367 } |
2368 | |
2508 /* | 2369 /* |
2509 Profiler profiler2("SpectrogramLayer::paintCache: draw image", true); | 2370 Profiler profiler2("SpectrogramLayer::paintCache: draw image", true); |
2510 | 2371 |
2511 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2372 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2512 std::cerr << "Painting " << w << "x" << rect.height() | 2373 std::cerr << "Painting " << w << "x" << rect.height() |
2587 return !morePaintingRequired; | 2448 return !morePaintingRequired; |
2588 | 2449 |
2589 // if (fftSuspended) fft->resume(); | 2450 // if (fftSuspended) fft->resume(); |
2590 } | 2451 } |
2591 | 2452 |
2453 bool | |
2454 SpectrogramLayer::checkAndScrollCache(PixmapCache &cache, QPainter &paint, | |
2455 long startFrame, int increment, | |
2456 int &x0, int &x1) const | |
2457 { | |
2458 int w = cache.pixmap->width(); | |
2459 | |
2460 if (cache.validArea.width() == 0) { | |
2461 x0 = 0; | |
2462 x1 = w; | |
2463 return true; // redraw everything | |
2464 } | |
2465 | |
2466 //!!! no, the gui thread will handle resizes -- we just draw | |
2467 //the area that's available in the cache. If the image is | |
2468 //enlarged, our valid area should remain the same and we'll | |
2469 //pick up on the discrepancy naturally (we hope) | |
2470 // if (cache.pixmap->width() == v->width() && | |
2471 // cache.pixmap->height() == v->height()) { | |
2472 | |
2473 if (cache.startFrame / increment == startFrame / increment && | |
2474 cache.validArea.x() <= x0 && | |
2475 cache.validArea.x() + cache.validArea.width() >= x1) { | |
2476 | |
2477 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2478 std::cerr << "SpectrogramLayer: pixmap cache good" << std::endl; | |
2479 #endif | |
2480 | |
2481 //!!! set a flag to that effect? | |
2482 | |
2483 x1 = x0; | |
2484 return false; | |
2485 | |
2486 } else { | |
2487 | |
2488 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2489 std::cerr << "SpectrogramLayer: pixmap cache partially OK" << std::endl; | |
2490 #endif | |
2491 | |
2492 int dx = cache.startFrame / increment - startFrame / increment; | |
2493 | |
2494 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2495 std::cerr << "SpectrogramLayer: dx = " << dx << " (pixmap cache " << cache.pixmap->width() << "x" << cache.pixmap->height() << ")" << std::endl; | |
2496 #endif | |
2497 | |
2498 if (dx != 0 && dx > -w && dx < w) { | |
2499 | |
2500 //#if defined(Q_WS_WIN32) || defined(Q_WS_MAC) | |
2501 // Copying a pixmap to itself doesn't work | |
2502 // properly on Windows or Mac (it only works when | |
2503 // moving in one direction). | |
2504 | |
2505 //!!! Need a utility function for this | |
2506 | |
2507 //!!! test again on Win and OS/X for images (above | |
2508 //comment applies to pixmaps) | |
2509 | |
2510 //!!! indeed, test again on linux for images too | |
2511 //-- I bet it doesn't work | |
2512 | |
2513 std::cerr << "SpectrogramLayer: copying from " << 0 | |
2514 << " to " << dx << std::endl; | |
2515 | |
2516 static QImage *tmp = 0; //!!! would need to be thread-local | |
2517 if (!tmp || | |
2518 tmp->width() != w || | |
2519 tmp->height() != cache.pixmap->height()) { | |
2520 delete tmp; | |
2521 tmp = new QImage(w, | |
2522 cache.pixmap->height(), | |
2523 QImage::Format_RGB32); | |
2524 } | |
2525 QPainter tmpPainter; | |
2526 tmpPainter.begin(tmp); | |
2527 tmpPainter.drawImage(0, 0, *cache.pixmap); | |
2528 tmpPainter.end(); | |
2529 paint.drawImage(dx, 0, *tmp); | |
2530 //#else | |
2531 // paint.drawImage(dx, 0, image); //!!! see above | |
2532 //#endif | |
2533 | |
2534 int px = cache.validArea.x(); | |
2535 int pw = cache.validArea.width(); | |
2536 | |
2537 if (dx < 0) { | |
2538 x0 = w + dx; | |
2539 x1 = w; | |
2540 px += dx; | |
2541 if (px < 0) { | |
2542 pw += px; | |
2543 px = 0; | |
2544 if (pw < 0) pw = 0; | |
2545 } | |
2546 } else { | |
2547 x0 = 0; | |
2548 x1 = dx; | |
2549 px += dx; | |
2550 if (px + pw > w) { | |
2551 pw = int(w) - px; | |
2552 if (pw < 0) pw = 0; | |
2553 } | |
2554 } | |
2555 | |
2556 cache.validArea = | |
2557 QRect(px, cache.validArea.y(), | |
2558 pw, cache.validArea.height()); | |
2559 } | |
2560 } | |
2561 // } else { | |
2562 //#ifdef DEBUG_SPECTROGRAM_REPAINT | |
2563 // std::cerr << "SpectrogramLayer: pixmap cache useless" << std::endl; | |
2564 // if (cache.pixmap->width() != v->width()) { | |
2565 // std::cerr << "(cache width " << cache.pixmap->width() | |
2566 // << " != " << v->width(); | |
2567 // } | |
2568 // if (cache.pixmap->height() != v->height()) { | |
2569 // std::cerr << "(cache height " << cache.pixmap->height() | |
2570 // << " != " << v->height(); | |
2571 // } | |
2572 //#endif | |
2573 // cache.validArea = QRect(); | |
2574 // } | |
2575 | |
2576 /*!!! | |
2577 if (updateViewMagnitudes(v)) { | |
2578 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2579 std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | |
2580 #endif | |
2581 recreateWholeCache = true; | |
2582 } else { | |
2583 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2584 std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; | |
2585 #endif | |
2586 } | |
2587 */ | |
2588 return false; | |
2589 } | |
2590 | |
2591 void | |
2592 SpectrogramLayer::selectPaintStrip(PixmapCache &cache, int &x0, int &x1, | |
2593 int paintBlockWidth) const | |
2594 { | |
2595 // This function narrows down the region [x0, x1) where x1 >= x0 | |
2596 // to a strip of approximately paintBlockWidth width. | |
2597 | |
2598 if (x1 - x0 < paintBlockWidth * 3 / 2) return; // it'll do | |
2599 | |
2600 if (cache.validArea.width() > 0) { | |
2601 | |
2602 // If part of the cache is known to be valid, select a strip | |
2603 // immediately to left or right of the valid part | |
2604 | |
2605 int vx0 = 0, vx1 = 0; // valid extents | |
2606 vx0 = cache.validArea.x(); | |
2607 vx1 = cache.validArea.x() + cache.validArea.width(); | |
2608 | |
2609 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2610 std::cerr << "x0 " << x0 << ", x1 " << x1 << ", vx0 " << vx0 << ", vx1 " << vx1 << ", paintBlockWidth " << paintBlockWidth << std::endl; | |
2611 #endif | |
2612 if (x0 < vx0) { | |
2613 if (x0 + paintBlockWidth < vx0) { | |
2614 x0 = vx0 - paintBlockWidth; | |
2615 // } else { | |
2616 // x0 = 0; | |
2617 } | |
2618 x1 = vx0; | |
2619 } else if (x0 >= vx1) { | |
2620 x0 = vx1; | |
2621 if (x1 > x0 + paintBlockWidth) { | |
2622 x1 = x0 + paintBlockWidth; | |
2623 } | |
2624 } else { | |
2625 // x0 is within the valid area | |
2626 if (x1 > vx1) { | |
2627 x0 = vx1; | |
2628 if (x0 + paintBlockWidth < x1) { | |
2629 x1 = x0 + paintBlockWidth; | |
2630 } | |
2631 } else { | |
2632 x1 = x0; // it's all valid, paint nothing | |
2633 } | |
2634 } | |
2635 | |
2636 } else { | |
2637 | |
2638 // No existing valid area; start at the middle, unless x0 is | |
2639 // already to the left of frame 0 | |
2640 | |
2641 //!!! no, for now just start at the middle always | |
2642 | |
2643 if (x1 > x0 + paintBlockWidth) { | |
2644 | |
2645 // int sfx = x1; // x for frame zero | |
2646 // if (startFrame < 0) sfx = v->getXForFrame(0); //!!! | |
2647 | |
2648 // if (startFrame < 0) sfx = | |
2649 // if (sfx >= x0 && sfx + paintBlockWidth <= x1) { | |
2650 // x0 = sfx; | |
2651 // x1 = x0 + paintBlockWidth; | |
2652 // } else { | |
2653 int mid = (x1 + x0) / 2; | |
2654 x0 = mid - paintBlockWidth/2; | |
2655 x1 = x0 + paintBlockWidth; | |
2656 // } | |
2657 } | |
2658 } | |
2659 } | |
2660 | |
2592 void | 2661 void |
2593 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const | 2662 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const |
2594 { | 2663 { |
2595 QPoint localPos; | 2664 QPoint localPos; |
2596 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) { | 2665 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) { |