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) {