comparison layer/SpectrogramLayer.cpp @ 330:846746e4e865 spectrogram-cache-rejig

* cache bits & bobs (wholly broken at the moment)
author Chris Cannam
date Fri, 16 Nov 2007 17:15:30 +0000
parents bbc9666cb961
children 6440e280122e
comparison
equal deleted inserted replaced
329:bbc9666cb961 330:846746e4e865
115 if (m_paintThread) { 115 if (m_paintThread) {
116 m_paintThread->exiting(); 116 m_paintThread->exiting();
117 m_paintThread->wait(); 117 m_paintThread->wait();
118 delete m_paintThread; 118 delete m_paintThread;
119 } 119 }
120
121 m_pixmapCacheMutex.lock();
122
123 while (!m_pixmapCaches.empty()) {
124
125 PixmapCache *cache = m_pixmapCaches.begin()->second;
126
127 cache->mutex.lock();
128 delete cache->pixmap;
129 cache->pixmap = 0;
130 cache->mutex.unlock();
131
132 delete cache;
133 m_pixmapCaches.erase(m_pixmapCaches.begin());
134 }
135
136 m_pixmapCacheMutex.unlock();
120 137
121 delete m_updateTimer; 138 delete m_updateTimer;
122 m_updateTimer = 0; 139 m_updateTimer = 0;
123 140
124 invalidateFFTModels(); 141 invalidateFFTModels();
554 571
555 void 572 void
556 SpectrogramLayer::invalidatePixmapCaches() 573 SpectrogramLayer::invalidatePixmapCaches()
557 { 574 {
558 QMutexLocker locker(&m_pixmapCacheMutex); 575 QMutexLocker locker(&m_pixmapCacheMutex);
576
559 for (ViewPixmapCache::iterator i = m_pixmapCaches.begin(); 577 for (ViewPixmapCache::iterator i = m_pixmapCaches.begin();
560 i != m_pixmapCaches.end(); ++i) { 578 i != m_pixmapCaches.end(); ++i) {
579
561 QMutexLocker locker(&i->second->mutex); 580 QMutexLocker locker(&i->second->mutex);
562 i->second->validArea = QRect(); 581 i->second->validArea = QRect();
563 } 582 }
564 } 583 }
565 584
566 void 585 void
567 SpectrogramLayer::invalidatePixmapCaches(size_t startFrame, size_t endFrame) 586 SpectrogramLayer::invalidatePixmapCaches(size_t startFrame, size_t endFrame)
568 { 587 {
569 QMutexLocker locker(&m_pixmapCacheMutex); 588 QMutexLocker locker(&m_pixmapCacheMutex);
589
570 for (ViewPixmapCache::iterator i = m_pixmapCaches.begin(); 590 for (ViewPixmapCache::iterator i = m_pixmapCaches.begin();
571 i != m_pixmapCaches.end(); ++i) { 591 i != m_pixmapCaches.end(); ++i) {
572 592
573 QMutexLocker locker(&i->second->mutex); 593 QMutexLocker locker(&i->second->mutex);
574 594
922 Layer::setLayerDormant(v, true); 942 Layer::setLayerDormant(v, true);
923 943
924 invalidatePixmapCaches(); 944 invalidatePixmapCaches();
925 945
926 m_pixmapCacheMutex.lock(); 946 m_pixmapCacheMutex.lock();
947
927 m_pixmapCaches[v]->mutex.lock(); 948 m_pixmapCaches[v]->mutex.lock();
949 delete m_pixmapCaches[v]->pixmap;
950 m_pixmapCaches[v]->pixmap = 0;
928 m_pixmapCaches[v]->mutex.unlock(); 951 m_pixmapCaches[v]->mutex.unlock();
929 // that only works if the paint thread never locks the 952
930 // specific mutex more than once for a given instance of a
931 // lock on the general mutex. really the data structure is
932 // unsuitable here.
933 delete m_pixmapCaches[v]; 953 delete m_pixmapCaches[v];
934 m_pixmapCaches.erase(v); 954 m_pixmapCaches.erase(v);
955
935 m_pixmapCacheMutex.unlock(); 956 m_pixmapCacheMutex.unlock();
936 957
937 if (m_fftModels.find(v) != m_fftModels.end()) { 958 if (m_fftModels.find(v) != m_fftModels.end()) {
938 959
939 if (m_sliceableModel == m_fftModels[v].first) { 960 if (m_sliceableModel == m_fftModels[v].first) {
1680 if (mag == m_viewMags[v]) return false; 1701 if (mag == m_viewMags[v]) return false;
1681 m_viewMags[v] = mag; 1702 m_viewMags[v] = mag;
1682 return true; 1703 return true;
1683 } 1704 }
1684 1705
1706
1707
1685 // Plan: 1708 // Plan:
1686 // 1709 //
1687 // - the QImage cache is managed by the GUI thread (which creates, 1710 // - the QImage cache is managed by the GUI thread (which creates,
1688 // sizes and destroys it). 1711 // sizes and destroys it).
1689 // 1712 //
1692 // - the GUI thread paint method should always just draw straight from 1715 // - the GUI thread paint method should always just draw straight from
1693 // cache without any lock, but it needs to check whether the cache is 1716 // cache without any lock, but it needs to check whether the cache is
1694 // complete and schedule another update if it isn't 1717 // complete and schedule another update if it isn't
1695 // 1718 //
1696 // - we need a mutex between cache construction/destruction activity 1719 // - we need a mutex between cache construction/destruction activity
1697 // and the paint thread 1720 // and the paint thread (I wonder whether we need a general mutex
1721 // between GUI thread changes to various parameters and paint thread
1722 // access to those parameters?)
1723 //!!! -> e.g. how is the access to FFTModels synchronised?
1724 //!!! -> and view magnitudes array?
1698 // 1725 //
1699 // - the paint thread needs to release the mutex occasionally so that 1726 // - the paint thread needs to release the mutex occasionally so that
1700 // cache positioning adjustments don't take forever. 1727 // cache positioning adjustments don't take forever.
1728 //
1729 // The cache covers a range from "somewhat before the start of the
1730 // view" to "somewhat after the end of it", and only (more or less)
1731 // the height of the view. (Or is it better for it to cover the full
1732 // height?) It is always at full resolution -- 1 pixel per bin in
1733 // both directions. When drawing from cache, the GUI thread does the
1734 // scaling.
1735
1736 //!!! and split into parent class (called e.g. DenseDataLayer) and
1737 //subclass; parent has GUI thread, subclass has paint thread and most
1738 //of the code.
1739
1701 1740
1702 void 1741 void
1703 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const 1742 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const
1704 { 1743 {
1705 // If the mutex for our cache is held, we should probably schedule 1744 // If the mutex for our cache is held, we should probably schedule
1709 // cache mutex only long enough to look up the cache object in the 1748 // cache mutex only long enough to look up the cache object in the
1710 // map, and then release it, retaining the specific mutex while it 1749 // map, and then release it, retaining the specific mutex while it
1711 // paints. The GUI thread should then never modify the cache 1750 // paints. The GUI thread should then never modify the cache
1712 // image without holding its specific mutex.) 1751 // image without holding its specific mutex.)
1713 1752
1714 Profiler profiler("SpectrogramLayer::paint", true); 1753 Profiler profiler("SpectrogramLayer::paint", false);
1715 1754
1716 QMutexLocker locker(&m_pixmapCacheMutex); 1755 QMutexLocker locker(&m_pixmapCacheMutex);
1756
1757 rect = v->rect(); //!!!
1717 1758
1718 PixmapCache *cache = m_pixmapCaches[v]; 1759 PixmapCache *cache = m_pixmapCaches[v];
1719 if (!cache) { 1760 if (!cache) {
1720 cache = new PixmapCache; 1761 cache = new PixmapCache;
1721 cache->pixmap = QImage(v->width(), v->height(), 1762 cache->pixmap = 0;
1722 QImage::Format_RGB32); 1763 m_pixmapCaches[v] = cache;
1764 cache->mutex.lock();
1765 cache->pixmap = new QImage(v->width(), v->height(),
1766 QImage::Format_RGB32);
1767 cache->mutex.unlock();
1723 #ifdef DEBUG_SPECTROGRAM_REPAINT 1768 #ifdef DEBUG_SPECTROGRAM_REPAINT
1724 std::cerr << "SpectrogramLayer::paint: Created new cache, size " 1769 std::cerr << "SpectrogramLayer::paint: Created new cache, size "
1725 << v->width() << "x" << v->height() << " (" 1770 << v->width() << "x" << v->height() << " ("
1726 << v->width() * v->height() * 4 << " bytes)" << std::endl; 1771 << v->width() * v->height() * 4 << " bytes)" << std::endl;
1727 #endif 1772 #endif
1728 m_pixmapCaches[v] = cache;
1729 return; //!!! prod paint thread 1773 return; //!!! prod paint thread
1730 } 1774 }
1731 1775
1732 if (!cache->mutex.tryLock()) { 1776 if (!cache->mutex.tryLock()) {
1733 std::cerr << "lock unavailable" << std::endl; 1777 std::cerr << "lock unavailable" << std::endl;
1734 paint.drawImage(rect,// & cache->validArea, 1778 paint.drawImage(rect,// & cache->validArea,
1735 cache->pixmap, 1779 *cache->pixmap,
1736 rect);// & cache->validArea); 1780 rect);// & cache->validArea);
1737 // v->update(rect); 1781 // v->update(rect);
1738 return; 1782 return;
1739 } 1783 }
1740 1784
1741 if (cache->pixmap.width() != v->width() || 1785 if (cache->pixmap->width() != v->width() ||
1742 cache->pixmap.height() != v->height()) { 1786 cache->pixmap->height() != v->height()) {
1743 cache->pixmap = cache->pixmap.scaled(v->width(), v->height()); 1787 QImage *newImage = new QImage
1788 (cache->pixmap->scaled(v->width(), v->height()));
1744 #ifdef DEBUG_SPECTROGRAM_REPAINT 1789 #ifdef DEBUG_SPECTROGRAM_REPAINT
1745 std::cerr << "SpectrogramLayer::paint: Rescaled cache to size " 1790 std::cerr << "SpectrogramLayer::paint: Rescaling cache to size "
1746 << v->width() << "x" << v->height() << " (" 1791 << v->width() << "x" << v->height() << " ("
1747 << v->width() * v->height() * 4 << " bytes)" << std::endl; 1792 << v->width() * v->height() * 4 << " bytes)" << std::endl;
1748 #endif 1793 #endif
1749 } 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();
1811 long cacheStartFrame = cache->startFrame;
1812 long xoff = (myStartFrame - cacheStartFrame) / getWindowIncrement();
1813
1814 std::cerr << "my start frame = " << myStartFrame << ", cache start frame = " << cacheStartFrame << std::endl;
1815
1816 QRect sourceRect = QRect(lrintf(rect.x() * ratio) + xoff,
1817 rect.y(),
1818 lrintf(rect.width() * ratio),
1819 rect.height());
1820
1821 std::cerr << "ratio = " << ratio << " (zoom " << v->getZoomLevel()
1822 << ", incr " << getWindowIncrement() << "); source rect "
1823 << sourceRect.x() << "," << sourceRect.y()
1824 << " " << sourceRect.width() << "x" << sourceRect.height()
1825 << ", target rect "
1826 << rect.x() << "," << rect.y()
1827 << " " << rect.width() << "x" << rect.height()
1828 << " (image " << cache->pixmap->width() << "x"
1829 << cache->pixmap->height() << ")"
1830 << std::endl;
1750 1831
1751 paint.drawImage(rect,// & cache->validArea, 1832 paint.drawImage(rect,// & cache->validArea,
1752 cache->pixmap, 1833 *cache->pixmap,
1753 rect);// & cache->validArea); 1834 sourceRect);// & cache->validArea);
1754 1835
1755 if (cache->startFrame != v->getStartFrame()) { 1836 if (cache->startFrame != v->getStartFrame()) {
1756 #ifdef DEBUG_SPECTROGRAM_REPAINT 1837 #ifdef DEBUG_SPECTROGRAM_REPAINT
1757 std::cerr << "SpectrogramLayer::paint(): Cache start frame " 1838 std::cerr << "SpectrogramLayer::paint(): Cache start frame "
1758 << cache->startFrame << " differs from view start frame " 1839 << cache->startFrame << " differs from view start frame "
1789 for (ViewPixmapCache::iterator i = m_layer->m_pixmapCaches.begin(); 1870 for (ViewPixmapCache::iterator i = m_layer->m_pixmapCaches.begin();
1790 i != m_layer->m_pixmapCaches.end(); ++i) { 1871 i != m_layer->m_pixmapCaches.end(); ++i) {
1791 views.insert(const_cast<View *>(i->first)); //!!! 1872 views.insert(const_cast<View *>(i->first)); //!!!
1792 } 1873 }
1793 m_layer->m_pixmapCacheMutex.unlock(); 1874 m_layer->m_pixmapCacheMutex.unlock();
1875
1876 bool workToDo = false;
1794 1877
1795 for (std::set<View *>::iterator vi = views.begin(); 1878 for (std::set<View *>::iterator vi = views.begin();
1796 vi != views.end(); ++vi) { 1879 vi != views.end(); ++vi) {
1797 1880
1798 m_layer->paintCache(*vi); 1881 if (m_layer->paintCache(*vi)) {
1882 if (!m_exiting) {
1883 std::cerr << "Cache complete: asking view to update"
1884 << std::endl;
1885 (*vi)->update();
1886 }
1887 } else {
1888 workToDo = true;
1889 }
1890
1799 if (m_exiting) break; 1891 if (m_exiting) break;
1800 } 1892 }
1801 1893
1802 if (!m_exiting) sleep(1); 1894 if (!m_exiting) {
1895 //!!! wait on condition
1896 if (workToDo) usleep(100);
1897 else sleep(1);
1898 }
1803 } 1899 }
1804 } 1900 }
1805 1901
1806 // return true if no more work to do, or can do no more 1902 // return true if no more work to do, or can do no more
1807 1903
1808 bool 1904 bool
1809 SpectrogramLayer::paintCache(View *v) const 1905 SpectrogramLayer::paintCache(View *v) const
1810 { 1906 {
1811 Profiler profiler("SpectrogramLayer::paintCache", true); 1907 Profiler profiler("SpectrogramLayer::paintCache", false);
1812 1908
1813 m_pixmapCacheMutex.lock(); 1909 m_pixmapCacheMutex.lock();
1814 1910
1815 PixmapCache *cacheptr = m_pixmapCaches[v]; 1911 PixmapCache *cacheptr = m_pixmapCaches[v];
1816 if (!cacheptr || cacheptr->pixmap.width() == 0) { 1912 if (!cacheptr || !cacheptr->pixmap || cacheptr->pixmap->width() == 0) {
1817 #ifdef DEBUG_SPECTROGRAM_REPAINT 1913 #ifdef DEBUG_SPECTROGRAM_REPAINT
1818 std::cerr << "SpectrogramLayer::paintCache(): No cache to paint onto" 1914 std::cerr << "SpectrogramLayer::paintCache(): No cache to paint onto"
1819 << std::endl; 1915 << std::endl;
1820 #endif 1916 #endif
1821 m_pixmapCacheMutex.unlock(); 1917 m_pixmapCacheMutex.unlock();
1824 1920
1825 PixmapCache &cache = *cacheptr; 1921 PixmapCache &cache = *cacheptr;
1826 QMutexLocker locker(&cache.mutex); 1922 QMutexLocker locker(&cache.mutex);
1827 m_pixmapCacheMutex.unlock(); 1923 m_pixmapCacheMutex.unlock();
1828 1924
1829 // establish rect to paint -- we want to paint the whole area that 1925 QImage &image = *cache.pixmap; //!!! rename to cache.image
1830 // is not known to be valid 1926
1831 1927 const DenseTimeValueModel *model = m_model;
1832 QRect rect = QRect(0, 0, cache.pixmap.width(), cache.pixmap.height()); 1928 if (!model || !model->isOK() || !model->isReady()) {
1833 1929 return false;
1834 QPainter paint(&cache.pixmap); 1930 }
1931
1932 //!!! mutex here -- we have the specific pixmap cache mutex held,
1933 //but only that one currently and there's no mutex for this stuff
1934 //in the other thread
1935
1936 //!!! what a big pile of crap
1937 long startFrame = v->getStartFrame();
1938 int increment = getWindowIncrement(); // signed for arithmetic purposes
1939 size_t fftNominal = m_fftSize; // the user-specified fft size
1940 size_t fftSize = getFFTSize(v); // the actual fft size (maybe padded)
1941 FFTModel *fft = getFFTModel(v);
1942 int sr = model->getSampleRate();
1943 size_t fmin = m_minFrequency;
1944 size_t fmax = m_maxFrequency;
1945 FrequencyScale frequencyScale = m_frequencyScale;
1946 BinDisplay binDisplay = m_binDisplay;
1947 float threshold = m_threshold;
1948 bool normalizeColumns = m_normalizeColumns;
1949 bool normalizeVisibleArea = m_normalizeVisibleArea;
1950 ColourScale colourScale = m_colourScale;
1951 float gain = m_gain;
1952 const Palette &palette = m_palette;
1953 int zpl = getZeroPadLevel(v) + 1;
1954
1955 if (!fft) {
1956 std::cerr << "ERROR: SpectrogramLayer::paintCache(): No FFT model, returning" << std::endl;
1957 return true;
1958 }
1959
1960
1961 std::cerr << "SpectrogramLayer::paintCache: start frame "
1962 << startFrame << ", increment " << increment << std::endl;
1963
1964
1965 int w = image.width();
1966 int h = image.height();
1967
1968
1969 // Establish rect to paint. We want to paint a not-too-large area
1970 // that is not known to be valid, adjacent to an area that is
1971 // known to be valid, such that the resulting known-valid area is
1972 // rectangular still. This doesn't really do that.
1973
1974 QRect rect = QRect(0, 0, w, h);
1975
1976 QPainter paint(cache.pixmap);
1835 1977
1836 #ifdef DEBUG_SPECTROGRAM_REPAINT 1978 #ifdef DEBUG_SPECTROGRAM_REPAINT
1837 std::cerr << "SpectrogramLayer::paintCache(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << std::endl; 1979 std::cerr << "SpectrogramLayer::paintCache(): m_model is " << model << ", window increment " << increment << std::endl;
1838 1980
1839 std::cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << std::endl; 1981 std::cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << std::endl;
1840 #endif 1982 #endif
1841 1983
1842 long startFrame = v->getStartFrame();
1843 if (startFrame < 0) m_candidateFillStartFrame = 0; 1984 if (startFrame < 0) m_candidateFillStartFrame = 0;
1844 else m_candidateFillStartFrame = startFrame; 1985 else m_candidateFillStartFrame = startFrame;
1845 1986
1846 if (!m_model || !m_model->isOK() || !m_model->isReady()) {
1847 return false;
1848 }
1849 /* 1987 /*
1850 if (isLayerDormant(v)) { 1988 if (isLayerDormant(v)) {
1851 std::cerr << "SpectrogramLayer::paintCache(): Layer is dormant, making it undormant again" << std::endl; 1989 std::cerr << "SpectrogramLayer::paintCache(): Layer is dormant, making it undormant again" << std::endl;
1852 } 1990 }
1853 1991
1856 // and accountable for when determining whether we need the cache 1994 // and accountable for when determining whether we need the cache
1857 // in the cache-fill thread above. 1995 // in the cache-fill thread above.
1858 //!!! no longer use cache-fill thread 1996 //!!! no longer use cache-fill thread
1859 const_cast<SpectrogramLayer *>(this)->Layer::setLayerDormant(v, false); 1997 const_cast<SpectrogramLayer *>(this)->Layer::setLayerDormant(v, false);
1860 */ 1998 */
1861 size_t fftSize = getFFTSize(v);
1862 FFTModel *fft = getFFTModel(v);
1863 if (!fft) {
1864 std::cerr << "ERROR: SpectrogramLayer::paintCache(): No FFT model, returning" << std::endl;
1865 return true;
1866 }
1867 1999
1868 #ifdef DEBUG_SPECTROGRAM_REPAINT 2000 #ifdef DEBUG_SPECTROGRAM_REPAINT
1869 std::cerr << "SpectrogramLayer::paintCache(): pixmap cache size " << cache.pixmap.width() << "x" << cache.pixmap.height() << std::endl; 2001 std::cerr << "SpectrogramLayer::paintCache(): pixmap cache size " << w << "x" << h << std::endl;
1870 std::cerr << "SpectrogramLayer::paintCache(): pixmap cache valid area " << cache.validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << std::endl; 2002 std::cerr << "SpectrogramLayer::paintCache(): pixmap cache valid area " << cache.validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << std::endl;
1871 #endif 2003 #endif
1872 2004
1873 int zoomLevel = v->getZoomLevel(); 2005 bool recreateWholeCache = true;
1874 2006
1875 int x0 = 0; 2007 int x0 = rect.left();
1876 int x1 = v->width(); 2008 int x1 = rect.right() + 1;
1877
1878 bool recreateWholePixmapCache = true;
1879
1880 x0 = rect.left();
1881 x1 = rect.right() + 1;
1882 2009
1883 if (cache.validArea.width() > 0) { 2010 if (cache.validArea.width() > 0) {
1884 2011
1885 if (int(cache.zoomLevel) == zoomLevel && 2012 //!!! no, the gui thread will handle resizes -- we just draw
1886 cache.pixmap.width() == v->width() && 2013 //the area that's available in the cache. If the image is
1887 cache.pixmap.height() == v->height()) { 2014 //enlarged, our valid area should remain the same and we'll
1888 2015 //pick up on the discrepancy naturally (we hope)
1889 if (v->getXForFrame(cache.startFrame) == 2016 // if (cache.pixmap->width() == v->width() &&
1890 v->getXForFrame(startFrame) && 2017 // cache.pixmap->height() == v->height()) {
2018
2019 if (cache.startFrame / increment == startFrame / increment &&
1891 cache.validArea.x() <= x0 && 2020 cache.validArea.x() <= x0 &&
1892 cache.validArea.x() + cache.validArea.width() >= x1) { 2021 cache.validArea.x() + cache.validArea.width() >= x1) {
1893 2022
1894 #ifdef DEBUG_SPECTROGRAM_REPAINT 2023 #ifdef DEBUG_SPECTROGRAM_REPAINT
1895 std::cerr << "SpectrogramLayer: pixmap cache good" << std::endl; 2024 std::cerr << "SpectrogramLayer: pixmap cache good" << std::endl;
1903 2032
1904 #ifdef DEBUG_SPECTROGRAM_REPAINT 2033 #ifdef DEBUG_SPECTROGRAM_REPAINT
1905 std::cerr << "SpectrogramLayer: pixmap cache partially OK" << std::endl; 2034 std::cerr << "SpectrogramLayer: pixmap cache partially OK" << std::endl;
1906 #endif 2035 #endif
1907 2036
1908 recreateWholePixmapCache = false; 2037 recreateWholeCache = false;
1909 2038
1910 int dx = v->getXForFrame(cache.startFrame) - 2039 int dx = cache.startFrame / increment - startFrame / increment;
1911 v->getXForFrame(startFrame);
1912 2040
1913 #ifdef DEBUG_SPECTROGRAM_REPAINT 2041 #ifdef DEBUG_SPECTROGRAM_REPAINT
1914 std::cerr << "SpectrogramLayer: dx = " << dx << " (pixmap cache " << cache.pixmap.width() << "x" << cache.pixmap.height() << ")" << std::endl; 2042 std::cerr << "SpectrogramLayer: dx = " << dx << " (pixmap cache " << cache.pixmap->width() << "x" << cache.pixmap->height() << ")" << std::endl;
1915 #endif 2043 #endif
1916 2044
1917 if (dx != 0 && 2045 if (dx != 0 && dx > -w && dx < w) {
1918 dx > -cache.pixmap.width() &&
1919 dx < cache.pixmap.width()) {
1920 2046
1921 #if defined(Q_WS_WIN32) || defined(Q_WS_MAC) 2047 #if defined(Q_WS_WIN32) || defined(Q_WS_MAC)
1922 // Copying a pixmap to itself doesn't work 2048 // Copying a pixmap to itself doesn't work
1923 // properly on Windows or Mac (it only works when 2049 // properly on Windows or Mac (it only works when
1924 // moving in one direction). 2050 // moving in one direction).
1925 2051
1926 //!!! Need a utility function for this 2052 //!!! Need a utility function for this
1927 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
1928 static QImage *tmpPixmap = 0; 2060 static QImage *tmpPixmap = 0;
1929 if (!tmpPixmap || 2061 if (!tmpPixmap ||
1930 tmpPixmap->width() != cache.pixmap.width() || 2062 tmpPixmap->width() != cache.pixmap->width() ||
1931 tmpPixmap->height() != cache.pixmap.height()) { 2063 tmpPixmap->height() != cache.pixmap->height()) {
1932 delete tmpPixmap; 2064 delete tmpPixmap;
1933 tmpPixmap = new QImage(cache.pixmap.width(), 2065 tmpPixmap = new QImage(cache.pixmap->width(),
1934 cache.pixmap.height(), 2066 cache.pixmap->height(),
1935 QImage::Format_RGB32); 2067 QImage::Format_RGB32);
1936 } 2068 }
1937 QPainter tmpPainter; 2069 QPainter tmpPainter;
1938 tmpPainter.begin(tmpPixmap); 2070 tmpPainter.begin(tmpPixmap);
1939 tmpPainter.drawImage(0, 0, cache.pixmap); 2071 tmpPainter.drawImage(0, 0, image);
1940 tmpPainter.end(); 2072 tmpPainter.end();
1941 paint.drawImage(dx, 0, *tmpPixmap); 2073 paint.drawImage(dx, 0, *tmpPixmap);
1942 #else 2074 #else
1943 paint.drawImage(dx, 0, cache.pixmap); 2075 paint.drawImage(dx, 0, image); //!!! see above
1944 #endif 2076 #endif
1945 2077
1946 int px = cache.validArea.x(); 2078 int px = cache.validArea.x();
1947 int pw = cache.validArea.width(); 2079 int pw = cache.validArea.width();
1948 2080
1949 if (dx < 0) { 2081 if (dx < 0) {
1950 x0 = cache.pixmap.width() + dx; 2082 x0 = w + dx;
1951 x1 = cache.pixmap.width(); 2083 x1 = w;
1952 px += dx; 2084 px += dx;
1953 if (px < 0) { 2085 if (px < 0) {
1954 pw += px; 2086 pw += px;
1955 px = 0; 2087 px = 0;
1956 if (pw < 0) pw = 0; 2088 if (pw < 0) pw = 0;
1957 } 2089 }
1958 } else { 2090 } else {
1959 x0 = 0; 2091 x0 = 0;
1960 x1 = dx; 2092 x1 = dx;
1961 px += dx; 2093 px += dx;
1962 if (px + pw > cache.pixmap.width()) { 2094 if (px + pw > w) {
1963 pw = int(cache.pixmap.width()) - px; 2095 pw = int(w) - px;
1964 if (pw < 0) pw = 0; 2096 if (pw < 0) pw = 0;
1965 } 2097 }
1966 } 2098 }
1967 2099
1968 cache.validArea = 2100 cache.validArea =
1969 QRect(px, cache.validArea.y(), 2101 QRect(px, cache.validArea.y(),
1970 pw, cache.validArea.height()); 2102 pw, cache.validArea.height());
1971 } 2103 }
1972 } 2104 }
1973 } else { 2105 // } else {
1974 #ifdef DEBUG_SPECTROGRAM_REPAINT 2106 //#ifdef DEBUG_SPECTROGRAM_REPAINT
1975 std::cerr << "SpectrogramLayer: pixmap cache useless" << std::endl; 2107 // std::cerr << "SpectrogramLayer: pixmap cache useless" << std::endl;
1976 if (int(cache.zoomLevel) != zoomLevel) { 2108 // if (cache.pixmap->width() != v->width()) {
1977 std::cerr << "(cache zoomLevel " << cache.zoomLevel 2109 // std::cerr << "(cache width " << cache.pixmap->width()
1978 << " != " << zoomLevel << ")" << std::endl; 2110 // << " != " << v->width();
1979 } 2111 // }
1980 if (cache.pixmap.width() != v->width()) { 2112 // if (cache.pixmap->height() != v->height()) {
1981 std::cerr << "(cache width " << cache.pixmap.width() 2113 // std::cerr << "(cache height " << cache.pixmap->height()
1982 << " != " << v->width(); 2114 // << " != " << v->height();
1983 } 2115 // }
1984 if (cache.pixmap.height() != v->height()) { 2116 //#endif
1985 std::cerr << "(cache height " << cache.pixmap.height() 2117 // cache.validArea = QRect();
1986 << " != " << v->height(); 2118 // }
1987 } 2119 }
1988 #endif 2120
1989 cache.validArea = QRect();
1990 }
1991 }
1992 /*!!! 2121 /*!!!
1993 if (updateViewMagnitudes(v)) { 2122 if (updateViewMagnitudes(v)) {
1994 #ifdef DEBUG_SPECTROGRAM_REPAINT 2123 #ifdef DEBUG_SPECTROGRAM_REPAINT
1995 std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; 2124 std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl;
1996 #endif 2125 #endif
1997 recreateWholePixmapCache = true; 2126 recreateWholeCache = true;
1998 } else { 2127 } else {
1999 #ifdef DEBUG_SPECTROGRAM_REPAINT 2128 #ifdef DEBUG_SPECTROGRAM_REPAINT
2000 std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl; 2129 std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl;
2001 #endif 2130 #endif
2002 } 2131 }
2003 */ 2132 */
2004 if (recreateWholePixmapCache) { 2133 if (recreateWholeCache) {
2005 x0 = 0; 2134 x0 = 0;
2006 x1 = rect.width(); 2135 x1 = w;
2007 } 2136 }
2008 2137
2009 struct timeval tv; 2138 struct timeval tv;
2010 (void)gettimeofday(&tv, 0); 2139 (void)gettimeofday(&tv, 0);
2011 RealTime mainPaintStart = RealTime::fromTimeval(tv); 2140 RealTime mainPaintStart = RealTime::fromTimeval(tv);
2012 2141
2013 int paintBlockWidth = m_lastPaintBlockWidth; 2142 int paintBlockWidth = m_lastPaintBlockWidth;
2014 2143
2015 if (paintBlockWidth == 0) { 2144 if (paintBlockWidth == 0) {
2016 paintBlockWidth = (300000 / zoomLevel); 2145 paintBlockWidth = (300000 / increment);
2017 } else { 2146 } else {
2018 RealTime lastTime = m_lastPaintTime; 2147 RealTime lastTime = m_lastPaintTime;
2019 while (lastTime > RealTime::fromMilliseconds(200) && 2148 while (lastTime > RealTime::fromMilliseconds(200) &&
2020 paintBlockWidth > 50) { 2149 paintBlockWidth > 50) {
2021 paintBlockWidth /= 2; 2150 paintBlockWidth /= 2;
2038 // Smaller heights can be used when painting from cache, but we 2167 // Smaller heights can be used when painting from cache, but we
2039 // want to ensure the cache is coherent without having to worry 2168 // want to ensure the cache is coherent without having to worry
2040 // about vertical matching of required and valid areas as well as 2169 // about vertical matching of required and valid areas as well as
2041 // horizontal. 2170 // horizontal.
2042 2171
2043 int h = v->height(); 2172 // int h = v->height();
2044 int w = x1 - x0; 2173 // int w = x1 - x0;
2045 2174
2046 #ifdef DEBUG_SPECTROGRAM_REPAINT 2175 #ifdef DEBUG_SPECTROGRAM_REPAINT
2047 std::cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << std::endl; 2176 std::cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << std::endl;
2048 #endif 2177 #endif
2049 2178
2051 // m_drawBuffer = QImage(w, h, QImage::Format_RGB32); 2180 // m_drawBuffer = QImage(w, h, QImage::Format_RGB32);
2052 // } 2181 // }
2053 2182
2054 // m_drawBuffer.fill(m_palette.getColour(0).rgb()); 2183 // m_drawBuffer.fill(m_palette.getColour(0).rgb());
2055 2184
2056 int sr = m_model->getSampleRate();
2057
2058 // Set minFreq and maxFreq to the frequency extents of the possibly 2185 // Set minFreq and maxFreq to the frequency extents of the possibly
2059 // zero-padded visible bin range, and displayMinFreq and displayMaxFreq 2186 // zero-padded visible bin range, and displayMinFreq and displayMaxFreq
2060 // to the actual scale frequency extents (presumably not zero padded). 2187 // to the actual scale frequency extents (presumably not zero padded).
2061 2188
2062 // If we are zero padding, we want to use the zero-padded 2189 // If we are zero padding, we want to use the zero-padded
2063 // equivalents of the bins that we would be using if not zero 2190 // equivalents of the bins that we would be using if not zero
2064 // padded, to avoid spaces at the top and bottom of the display. 2191 // padded, to avoid spaces at the top and bottom of the display.
2065 2192
2066 // Note fftSize is the actual zero-padded fft size, m_fftSize the 2193 //!!! --> we weren't actually using minFreq or maxFreq -- so just
2194 // set our new fmin/fmax to the display extents
2195
2196 // Note fftSize is the actual zero-padded fft size, fftNominal the
2067 // nominal fft size. 2197 // nominal fft size.
2068 2198
2069 size_t maxbin = m_fftSize / 2; 2199 size_t maxbin = fftNominal / 2;
2070 if (m_maxFrequency > 0) { 2200 if (fmax > 0) {
2071 maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.001); 2201 maxbin = int((double(fmax) * fftNominal) / sr + 0.001);
2072 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; 2202 if (maxbin > fftNominal / 2) maxbin = fftNominal / 2;
2073 } 2203 }
2074 2204
2075 size_t minbin = 1; 2205 size_t minbin = 1;
2076 if (m_minFrequency > 0) { 2206 if (fmin > 0) {
2077 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.001); 2207 minbin = int((double(fmin) * fftNominal) / sr + 0.001);
2078 // std::cerr << "m_minFrequency = " << m_minFrequency << " -> minbin = " << minbin << std::endl;
2079 if (minbin < 1) minbin = 1; 2208 if (minbin < 1) minbin = 1;
2080 if (minbin >= maxbin) minbin = maxbin - 1; 2209 if (minbin >= maxbin) minbin = maxbin - 1;
2081 } 2210 }
2082 2211
2083 int zpl = getZeroPadLevel(v) + 1;
2084 minbin = minbin * zpl; 2212 minbin = minbin * zpl;
2085 maxbin = (maxbin + 1) * zpl - 1; 2213 maxbin = (maxbin + 1) * zpl - 1;
2086 2214
2087 float minFreq = (float(minbin) * sr) / fftSize; 2215 fmin = (float(minbin) * sr) / fftNominal;
2088 float maxFreq = (float(maxbin) * sr) / fftSize; 2216 fmax = (float(maxbin) * sr) / fftNominal;
2089
2090 float displayMinFreq = minFreq;
2091 float displayMaxFreq = maxFreq;
2092
2093 if (fftSize != m_fftSize) {
2094 displayMinFreq = getEffectiveMinFrequency();
2095 displayMaxFreq = getEffectiveMaxFrequency();
2096 }
2097
2098 // std::cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << std::endl;
2099 2217
2100 float ymag[h]; 2218 float ymag[h];
2101 float ydiv[h]; 2219 float ydiv[h];
2102 float yval[maxbin + 1]; //!!! cache this? 2220 float yval[maxbin + 1]; //!!! cache this?
2103 2221
2104 size_t increment = getWindowIncrement(); 2222 bool logarithmic = (frequencyScale == LogFrequencyScale);
2105
2106 bool logarithmic = (m_frequencyScale == LogFrequencyScale);
2107 2223
2108 for (size_t q = minbin; q <= maxbin; ++q) { 2224 for (size_t q = minbin; q <= maxbin; ++q) {
2109 float f0 = (float(q) * sr) / fftSize; 2225 float f0 = (float(q) * sr) / fftSize;
2110 yval[q] = v->getYForFrequency(f0, displayMinFreq, displayMaxFreq, 2226 yval[q] = v->getYForFrequency(f0, fmin, fmax, logarithmic);
2111 logarithmic);
2112 // std::cerr << "min: " << minFreq << ", max: " << maxFreq << ", yval[" << q << "]: " << yval[q] << std::endl; 2227 // std::cerr << "min: " << minFreq << ", max: " << maxFreq << ", yval[" << q << "]: " << yval[q] << std::endl;
2113 } 2228 }
2114 2229
2115 MagnitudeRange overallMag = m_viewMags[v]; 2230 MagnitudeRange overallMag = m_viewMags[v];
2116 // bool overallMagChanged = false; 2231 // bool overallMagChanged = false;
2120 bool interpolate = false; 2235 bool interpolate = false;
2121 Preferences::SpectrogramSmoothing smoothing = 2236 Preferences::SpectrogramSmoothing smoothing =
2122 Preferences::getInstance()->getSpectrogramSmoothing(); 2237 Preferences::getInstance()->getSpectrogramSmoothing();
2123 if (smoothing == Preferences::SpectrogramInterpolated || 2238 if (smoothing == Preferences::SpectrogramInterpolated ||
2124 smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated) { 2239 smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated) {
2125 if (m_binDisplay != PeakBins && 2240 if (binDisplay != PeakBins &&
2126 m_binDisplay != PeakFrequencies) { 2241 binDisplay != PeakFrequencies) {
2127 interpolate = true; 2242 interpolate = true;
2128 } 2243 }
2129 } 2244 }
2130 2245
2131 #ifdef DEBUG_SPECTROGRAM_REPAINT
2132 std::cerr << ((float(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << std::endl;
2133 #endif
2134
2135 bool runOutOfData = false; 2246 bool runOutOfData = false;
2136 2247
2137 for (int x = 0; x < w; ++x) { 2248 for (int x = 0; x < (x1 - x0); ++x) {
2138 2249
2139 if (runOutOfData) break; 2250 if (runOutOfData) break;
2140 2251
2141 for (int y = 0; y < h; ++y) { 2252 for (int y = 0; y < h; ++y) {
2142 ymag[y] = 0.f; 2253 ymag[y] = 0.f;
2143 ydiv[y] = 0.f; 2254 ydiv[y] = 0.f;
2144 } 2255 }
2145 2256
2146 float s0 = 0, s1 = 0; 2257 int col = (startFrame / increment) + x0 + x;
2147 2258
2148 if (!getXBinRange(v, x0 + x, s0, s1)) { 2259 // std::cerr << "x = " << x << ", col = " << col << std::endl;
2149 // assert(x <= m_drawBuffer.width()); 2260
2150 continue; 2261 if (col >= int(fft->getWidth())) {
2262 continue;
2151 } 2263 }
2152 2264
2153 int s0i = int(s0 + 0.001); 2265 if (!fft->isColumnAvailable(col)) {
2154 int s1i = int(s1);
2155
2156 if (s1i >= int(fft->getWidth())) {
2157 if (s0i >= int(fft->getWidth())) {
2158 continue;
2159 } else {
2160 s1i = s0i;
2161 }
2162 }
2163
2164 for (int s = s0i; s <= s1i; ++s) {
2165
2166 if (!fft->isColumnAvailable(s)) {
2167 #ifdef DEBUG_SPECTROGRAM_REPAINT 2266 #ifdef DEBUG_SPECTROGRAM_REPAINT
2168 std::cerr << "Met unavailable column at col " << s << std::endl; 2267 std::cerr << "Met unavailable column at col " << col << std::endl;
2169 #endif 2268 #endif
2170 // continue; 2269 runOutOfData = true;
2171 runOutOfData = true; 2270 break;
2172 break; 2271 }
2173 }
2174 2272
2175 /* 2273 /*
2176 if (!fftSuspended) { 2274 if (!fftSuspended) {
2177 fft->suspendWrites(); 2275 fft->suspendWrites();
2178 fftSuspended = true; 2276 fftSuspended = true;
2179 } 2277 }
2180 */ 2278 */
2181 MagnitudeRange mag; 2279
2182 2280 MagnitudeRange mag;
2183 FFTModel::PeakSet peaks; 2281
2184 if (m_binDisplay == PeakFrequencies && 2282 FFTModel::PeakSet peaks;
2185 s < int(fft->getWidth()) - 1) { 2283 if (binDisplay == PeakFrequencies &&
2186 peaks = fft->getPeakFrequencies(FFTModel::AllPeaks, 2284 col < int(fft->getWidth()) - 1) {
2187 s, 2285 peaks = fft->getPeakFrequencies(FFTModel::AllPeaks,
2188 minbin, maxbin - 1); 2286 col,
2287 minbin, maxbin - 1);
2288 }
2289
2290 for (size_t q = minbin; q < maxbin; ++q) {
2291
2292 float y0 = yval[q + 1];
2293 float y1 = yval[q];
2294
2295 if (binDisplay == PeakBins) {
2296 if (!fft->isLocalPeak(col, q)) continue;
2189 } 2297 }
2190 2298 if (binDisplay == PeakFrequencies) {
2191 for (size_t q = minbin; q < maxbin; ++q) { 2299 if (peaks.find(q) == peaks.end()) continue;
2192 2300 }
2193 float y0 = yval[q + 1]; 2301
2194 float y1 = yval[q]; 2302 if (threshold != 0.f &&
2195 2303 !fft->isOverThreshold(col, q, threshold * (fftNominal/2))) {
2196 if (m_binDisplay == PeakBins) { 2304 continue;
2197 if (!fft->isLocalPeak(s, q)) continue; 2305 }
2198 } 2306
2199 if (m_binDisplay == PeakFrequencies) { 2307 if (binDisplay == PeakFrequencies) {
2200 if (peaks.find(q) == peaks.end()) continue; 2308 y0 = y1 = v->getYForFrequency
2309 (peaks[q], fmin, fmax, logarithmic);
2310 }
2311
2312 int y0i = int(y0 + 0.001);
2313 int y1i = int(y1);
2314
2315 float value;
2316
2317 if (colourScale == PhaseColourScale) {
2318 value = fft->getPhaseAt(col, q);
2319 } else if (normalizeColumns) {
2320 value = fft->getNormalizedMagnitudeAt(col, q);
2321 mag.sample(value);
2322 value *= gain;
2323 } else {
2324 value = fft->getMagnitudeAt(col, q) / (fftNominal/2);
2325 mag.sample(value);
2326 value *= gain;
2327 }
2328
2329 if (interpolate) {
2330
2331 int ypi = y0i;
2332 if (q < maxbin - 1) ypi = int(yval[q + 2]);
2333
2334 for (int y = ypi; y <= y1i; ++y) {
2335
2336 if (y < 0 || y >= h) continue;
2337
2338 float yprop = 1.f;
2339 float iprop = yprop;
2340
2341 if (ypi < y0i && y <= y0i) {
2342
2343 float half = float(y0i - ypi) / 2;
2344 float dist = y - (ypi + half);
2345
2346 if (dist >= 0) {
2347 iprop = (iprop * dist) / half;
2348 ymag[y] += iprop * value;
2349 }
2350 } else {
2351 if (y1i > y0i) {
2352
2353 float half = float(y1i - y0i) / 2;
2354 float dist = y - (y0i + half);
2355
2356 if (dist >= 0) {
2357 iprop = (iprop * (half - dist)) / half;
2358 }
2359 }
2360
2361 ymag[y] += iprop * value;
2362 ydiv[y] += yprop;
2363 }
2201 } 2364 }
2202
2203 if (m_threshold != 0.f &&
2204 !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) {
2205 continue;
2206 }
2207
2208 float sprop = 1.0;
2209 if (s == s0i) sprop *= (s + 1) - s0;
2210 if (s == s1i) sprop *= s1 - s;
2211
2212 if (m_binDisplay == PeakFrequencies) {
2213 y0 = y1 = v->getYForFrequency
2214 (peaks[q], displayMinFreq, displayMaxFreq, logarithmic);
2215 }
2216
2217 int y0i = int(y0 + 0.001);
2218 int y1i = int(y1);
2219
2220 float value;
2221 2365
2222 if (m_colourScale == PhaseColourScale) { 2366 } else {
2223 value = fft->getPhaseAt(s, q); 2367
2224 } else if (m_normalizeColumns) { 2368 for (int y = y0i; y <= y1i; ++y) {
2225 value = fft->getNormalizedMagnitudeAt(s, q);
2226 mag.sample(value);
2227 value *= m_gain;
2228 } else {
2229 value = fft->getMagnitudeAt(s, q) / (m_fftSize/2);
2230 mag.sample(value);
2231 value *= m_gain;
2232 }
2233
2234 if (interpolate) {
2235 2369
2236 int ypi = y0i; 2370 if (y < 0 || y >= h) continue;
2237 if (q < maxbin - 1) ypi = int(yval[q + 2]);
2238
2239 for (int y = ypi; y <= y1i; ++y) {
2240 2371
2372 float yprop = 1.f;
2373 if (y == y0i) yprop *= (y + 1) - y0;
2374 if (y == y1i) yprop *= y1 - y;
2375
2376 for (int y = y0i; y <= y1i; ++y) {
2377
2241 if (y < 0 || y >= h) continue; 2378 if (y < 0 || y >= h) continue;
2242 2379
2243 float yprop = sprop; 2380 float yprop = 1.f;
2244 float iprop = yprop;
2245
2246 if (ypi < y0i && y <= y0i) {
2247
2248 float half = float(y0i - ypi) / 2;
2249 float dist = y - (ypi + half);
2250
2251 if (dist >= 0) {
2252 iprop = (iprop * dist) / half;
2253 ymag[y] += iprop * value;
2254 }
2255 } else {
2256 if (y1i > y0i) {
2257
2258 float half = float(y1i - y0i) / 2;
2259 float dist = y - (y0i + half);
2260
2261 if (dist >= 0) {
2262 iprop = (iprop * (half - dist)) / half;
2263 }
2264 }
2265
2266 ymag[y] += iprop * value;
2267 ydiv[y] += yprop;
2268 }
2269 }
2270
2271 } else {
2272
2273 for (int y = y0i; y <= y1i; ++y) {
2274
2275 if (y < 0 || y >= h) continue;
2276
2277 float yprop = sprop;
2278 if (y == y0i) yprop *= (y + 1) - y0; 2381 if (y == y0i) yprop *= (y + 1) - y0;
2279 if (y == y1i) yprop *= y1 - y; 2382 if (y == y1i) yprop *= y1 - y;
2280 2383 ymag[y] += yprop * value;
2281 for (int y = y0i; y <= y1i; ++y) { 2384 ydiv[y] += yprop;
2282
2283 if (y < 0 || y >= h) continue;
2284
2285 float yprop = sprop;
2286 if (y == y0i) yprop *= (y + 1) - y0;
2287 if (y == y1i) yprop *= y1 - y;
2288 ymag[y] += yprop * value;
2289 ydiv[y] += yprop;
2290 }
2291 } 2385 }
2292 } 2386 }
2293 } 2387 }
2388 }
2294 /* 2389 /*
2295 if (mag.isSet()) { 2390 if (mag.isSet()) {
2296 2391
2297 if (s >= int(m_columnMags.size())) { 2392 if (s >= int(m_columnMags.size())) {
2298 std::cerr << "INTERNAL ERROR: " << s << " >= " 2393 std::cerr << "INTERNAL ERROR: " << s << " >= "
2308 std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl; 2403 std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl;
2309 #endif 2404 #endif
2310 } 2405 }
2311 } 2406 }
2312 */ 2407 */
2313 }
2314 2408
2315 for (int y = 0; y < h; ++y) { 2409 for (int y = 0; y < h; ++y) {
2316 2410
2317 if (ydiv[y] > 0.0) { 2411 if (ydiv[y] > 0.0) {
2318 2412
2319 unsigned char pixel = 0; 2413 unsigned char pixel = 0;
2320 2414
2321 float avg = ymag[y] / ydiv[y]; 2415 float avg = ymag[y] / ydiv[y];
2322 pixel = getDisplayValue(v, avg); 2416 pixel = getDisplayValue(v, avg); //!!!???
2323 2417
2324 // assert(x <= m_drawBuffer.width()); 2418 // assert(x <= m_drawBuffer.width());
2325 assert(x <= cache.pixmap.width()); 2419 assert(x <= w);
2326 QColor c = m_palette.getColour(pixel); 2420 QColor c = palette.getColour(pixel);
2327 2421
2328 if (x0 + x >= cache.pixmap.width()) { 2422 if (x0 + x >= w) {
2329 std::cerr << "INTERNAL ERROR: " << x0 << "+" 2423 std::cerr << "INTERNAL ERROR: " << x0 << "+"
2330 << x << " >= " << cache.pixmap.width() 2424 << x << " >= " << w
2331 << " at SpectrogramLayer.cpp:" 2425 << " at SpectrogramLayer.cpp:"
2332 << __LINE__ << std::endl; 2426 << __LINE__ << std::endl;
2333 continue; 2427 continue;
2334 } 2428 }
2335 2429
2336 if (y >= cache.pixmap.height()) { 2430 if (y >= h) {
2337 std::cerr << "INTERNAL ERROR: " << y 2431 std::cerr << "INTERNAL ERROR: " << y
2338 << " >= " << cache.pixmap.height() 2432 << " >= " << h
2339 << " at SpectrogramLayer.cpp:" 2433 << " at SpectrogramLayer.cpp:"
2340 << __LINE__ << std::endl; 2434 << __LINE__ << std::endl;
2341 continue; 2435 continue;
2342 } 2436 }
2343 2437
2344 assert(x0 + x < cache.pixmap.width()); 2438 assert(x0 + x < w);
2345 assert(y < cache.pixmap.height()); 2439 assert(y < h);
2346 2440
2347 cache.pixmap.setPixel(x0 + x, y, 2441 image.setPixel(x0 + x, y,
2348 qRgb(c.red(), c.green(), c.blue())); 2442 qRgb(c.red(), c.green(), c.blue()));
2349 } 2443 }
2350 } 2444 }
2351 } 2445 }
2352 /* 2446 /*
2353 if (overallMagChanged) { 2447 if (overallMagChanged) {
2397 cache.validArea.height()); 2491 cache.validArea.height());
2398 2492
2399 } else { 2493 } else {
2400 if (x1 > x0 + paintBlockWidth) { 2494 if (x1 > x0 + paintBlockWidth) {
2401 int sfx = x1; 2495 int sfx = x1;
2402 if (startFrame < 0) sfx = v->getXForFrame(0); 2496 if (startFrame < 0) sfx = v->getXForFrame(0); //!!!
2403 if (sfx >= x0 && sfx + paintBlockWidth <= x1) { 2497 if (sfx >= x0 && sfx + paintBlockWidth <= x1) {
2404 x0 = sfx; 2498 x0 = sfx;
2405 x1 = x0 + paintBlockWidth; 2499 x1 = x0 + paintBlockWidth;
2406 } else { 2500 } else {
2407 int mid = (x1 + x0) / 2; 2501 int mid = (x1 + x0) / 2;
2420 << " to window at " << x0 << "," << rect.y() << std::endl; 2514 << " to window at " << x0 << "," << rect.y() << std::endl;
2421 #endif 2515 #endif
2422 2516
2423 paint.drawImage(x0, rect.y(), m_drawBuffer, 0, rect.y(), w, rect.height()); 2517 paint.drawImage(x0, rect.y(), m_drawBuffer, 0, rect.y(), w, rect.height());
2424 2518
2425 if (recreateWholePixmapCache) { 2519 if (recreateWholeCache) {
2426 // cache.pixmap = QPixmap(v->width(), h); 2520 // cache.pixmap = QPixmap(v->width(), h);
2427 cache.pixmap = QImage(v->width(), h, QImage::Format_RGB32); 2521 cache.pixmap = QImage(v->width(), h, QImage::Format_RGB32);
2428 } 2522 }
2429 2523
2430 #ifdef DEBUG_SPECTROGRAM_REPAINT 2524 #ifdef DEBUG_SPECTROGRAM_REPAINT
2439 */ 2533 */
2440 /* 2534 /*
2441 if (!m_normalizeVisibleArea || !overallMagChanged) { 2535 if (!m_normalizeVisibleArea || !overallMagChanged) {
2442 */ 2536 */
2443 cache.startFrame = startFrame; 2537 cache.startFrame = startFrame;
2444 cache.zoomLevel = zoomLevel;
2445 2538
2446 bool morePaintingRequired = false; 2539 bool morePaintingRequired = false;
2447 2540
2448 if (cache.validArea.x() > 0) { 2541 if (cache.validArea.x() > 0) {
2449 #ifdef DEBUG_SPECTROGRAM_REPAINT 2542 #ifdef DEBUG_SPECTROGRAM_REPAINT
2453 // v->update(0, 0, cache.validArea.x(), h); 2546 // v->update(0, 0, cache.validArea.x(), h);
2454 morePaintingRequired = true; 2547 morePaintingRequired = true;
2455 } 2548 }
2456 2549
2457 if (cache.validArea.x() + cache.validArea.width() < 2550 if (cache.validArea.x() + cache.validArea.width() <
2458 cache.pixmap.width()) { 2551 image.width()) {
2459 #ifdef DEBUG_SPECTROGRAM_REPAINT 2552 #ifdef DEBUG_SPECTROGRAM_REPAINT
2460 std::cerr << "SpectrogramLayer::paintCache() updating right (" 2553 std::cerr << "SpectrogramLayer::paintCache() updating right ("
2461 << cache.validArea.x() + cache.validArea.width() 2554 << cache.validArea.x() + cache.validArea.width()
2462 << ", " 2555 << ", "
2463 << cache.pixmap.width() - (cache.validArea.x() + 2556 << image.width() - (cache.validArea.x() +
2464 cache.validArea.width()) 2557 cache.validArea.width())
2465 << ")" << std::endl; 2558 << ")" << std::endl;
2466 #endif 2559 #endif
2467 // v->update(cache.validArea.x() + cache.validArea.width(), 2560 // v->update(cache.validArea.x() + cache.validArea.width(),
2468 // 0, 2561 // 0,
2469 // cache.pixmap.width() - (cache.validArea.x() + 2562 // image.width() - (cache.validArea.x() +
2470 // cache.validArea.width()), 2563 // cache.validArea.width()),
2471 // h); 2564 // h);
2472 morePaintingRequired = true; 2565 morePaintingRequired = true;
2473 } 2566 }
2474 /* 2567 /*
2482 // illuminateLocalFeatures(v, paint); 2575 // illuminateLocalFeatures(v, paint);
2483 2576
2484 #ifdef DEBUG_SPECTROGRAM_REPAINT 2577 #ifdef DEBUG_SPECTROGRAM_REPAINT
2485 std::cerr << "SpectrogramLayer::paintCache() returning" << std::endl; 2578 std::cerr << "SpectrogramLayer::paintCache() returning" << std::endl;
2486 #endif 2579 #endif
2580
2581 paint.end();
2487 2582
2488 m_lastPaintBlockWidth = paintBlockWidth; 2583 m_lastPaintBlockWidth = paintBlockWidth;
2489 (void)gettimeofday(&tv, 0); 2584 (void)gettimeofday(&tv, 0);
2490 m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart; 2585 m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart;
2491 2586
2655 { 2750 {
2656 //!!! check cache consistency 2751 //!!! check cache consistency
2657 QMutexLocker locker(&m_pixmapCacheMutex); 2752 QMutexLocker locker(&m_pixmapCacheMutex);
2658 2753
2659 PixmapCache *cache = m_pixmapCaches[v]; 2754 PixmapCache *cache = m_pixmapCaches[v];
2660 if (!cache) return; 2755 if (!cache || !cache->pixmap) return;
2661 2756
2662 std::cerr << "cache width: " << cache->pixmap.width() << ", height: " 2757 std::cerr << "cache width: " << cache->pixmap->width() << ", height: "
2663 << cache->pixmap.height() << std::endl; 2758 << cache->pixmap->height() << std::endl;
2664 2759
2665 QImage image = cache->pixmap /*.toImage() */; 2760 //!!! lock
2761
2762 QImage image = *cache->pixmap /*.toImage() */;
2666 2763
2667 ImageRegionFinder finder; 2764 ImageRegionFinder finder;
2668 QRect rect = finder.findRegionExtents(&image, e->pos()); 2765 QRect rect = finder.findRegionExtents(&image, e->pos());
2669 if (rect.isValid()) { 2766 if (rect.isValid()) {
2670 MeasureRect mr; 2767 MeasureRect mr;
2938 { 3035 {
2939 if (!m_model || !m_model->isOK()) { 3036 if (!m_model || !m_model->isOK()) {
2940 return; 3037 return;
2941 } 3038 }
2942 3039
2943 Profiler profiler("SpectrogramLayer::paintVerticalScale", true); 3040 Profiler profiler("SpectrogramLayer::paintVerticalScale", false);
2944 3041
2945 //!!! cache this? 3042 //!!! cache this?
2946 3043
2947 int h = rect.height(), w = rect.width(); 3044 int h = rect.height(), w = rect.width();
2948 3045