comparison layer/SpectrogramLayer.cpp @ 978:64c2b3a4435a 3.0-integration

Merge from branch osx-retina
author Chris Cannam
date Fri, 26 Jun 2015 14:10:40 +0100
parents b8187c83b93a e39d5d2734ed
children 98827470ada2
comparison
equal deleted inserted replaced
977:f40ccbf228c2 978:64c2b3a4435a
576 { 576 {
577 for (ViewImageCache::iterator i = m_imageCaches.begin(); 577 for (ViewImageCache::iterator i = m_imageCaches.begin();
578 i != m_imageCaches.end(); ++i) { 578 i != m_imageCaches.end(); ++i) {
579 579
580 //!!! when are views removed from the map? on setLayerDormant? 580 //!!! when are views removed from the map? on setLayerDormant?
581 const View *v = i->first; 581 const LayerGeometryProvider *v = i->first;
582 582
583 #ifdef DEBUG_SPECTROGRAM_REPAINT 583 #ifdef DEBUG_SPECTROGRAM_REPAINT
584 SVDEBUG << "SpectrogramLayer::invalidateImageCaches(" 584 SVDEBUG << "SpectrogramLayer::invalidateImageCaches("
585 << startFrame << ", " << endFrame << "): view range is " 585 << startFrame << ", " << endFrame << "): view range is "
586 << v->getStartFrame() << ", " << v->getEndFrame() 586 << v->getStartFrame() << ", " << v->getEndFrame()
603 #ifdef DEBUG_SPECTROGRAM_REPAINT 603 #ifdef DEBUG_SPECTROGRAM_REPAINT
604 SVDEBUG << "clipping from 0 to " << x-1 << endl; 604 SVDEBUG << "clipping from 0 to " << x-1 << endl;
605 #endif 605 #endif
606 if (x > 1) { 606 if (x > 1) {
607 i->second.validArea &= 607 i->second.validArea &=
608 QRect(0, 0, x-1, v->height()); 608 QRect(0, 0, x-1, v->getPaintHeight());
609 } else { 609 } else {
610 i->second.validArea = QRect(); 610 i->second.validArea = QRect();
611 } 611 }
612 } else { 612 } else {
613 if (int(endFrame) < v->getStartFrame()) { 613 if (int(endFrame) < v->getStartFrame()) {
616 #endif 616 #endif
617 return; 617 return;
618 } 618 }
619 int x = v->getXForFrame(endFrame); 619 int x = v->getXForFrame(endFrame);
620 #ifdef DEBUG_SPECTROGRAM_REPAINT 620 #ifdef DEBUG_SPECTROGRAM_REPAINT
621 SVDEBUG << "clipping from " << x+1 << " to " << v->width() 621 SVDEBUG << "clipping from " << x+1 << " to " << v->getPaintWidth()
622 << endl; 622 << endl;
623 #endif 623 #endif
624 if (x < v->width()) { 624 if (x < v->getPaintWidth()) {
625 i->second.validArea &= 625 i->second.validArea &=
626 QRect(x+1, 0, v->width()-(x+1), v->height()); 626 QRect(x+1, 0, v->getPaintWidth()-(x+1), v->getPaintHeight());
627 } else { 627 } else {
628 i->second.validArea = QRect(); 628 i->second.validArea = QRect();
629 } 629 }
630 } 630 }
631 631
989 { 989 {
990 return m_normalizeVisibleArea; 990 return m_normalizeVisibleArea;
991 } 991 }
992 992
993 void 993 void
994 SpectrogramLayer::setLayerDormant(const View *v, bool dormant) 994 SpectrogramLayer::setLayerDormant(const LayerGeometryProvider *v, bool dormant)
995 { 995 {
996 if (dormant) { 996 if (dormant) {
997 997
998 #ifdef DEBUG_SPECTROGRAM_REPAINT 998 #ifdef DEBUG_SPECTROGRAM_REPAINT
999 SVDEBUG << "SpectrogramLayer::setLayerDormant(" << dormant << ")" 999 SVDEBUG << "SpectrogramLayer::setLayerDormant(" << dormant << ")"
1004 return; 1004 return;
1005 } 1005 }
1006 1006
1007 Layer::setLayerDormant(v, true); 1007 Layer::setLayerDormant(v, true);
1008 1008
1009 const View *view = v->getView();
1010
1009 invalidateImageCaches(); 1011 invalidateImageCaches();
1010 m_imageCaches.erase(v); 1012 m_imageCaches.erase(view);
1011 1013
1012 if (m_fftModels.find(v) != m_fftModels.end()) { 1014 if (m_fftModels.find(view) != m_fftModels.end()) {
1013 1015
1014 if (m_sliceableModel == m_fftModels[v].first) { 1016 if (m_sliceableModel == m_fftModels[view].first) {
1015 bool replaced = false; 1017 bool replaced = false;
1016 for (ViewFFTMap::iterator i = m_fftModels.begin(); 1018 for (ViewFFTMap::iterator i = m_fftModels.begin();
1017 i != m_fftModels.end(); ++i) { 1019 i != m_fftModels.end(); ++i) {
1018 if (i->second.first != m_sliceableModel) { 1020 if (i->second.first != m_sliceableModel) {
1019 emit sliceableModelReplaced(m_sliceableModel, i->second.first); 1021 emit sliceableModelReplaced(m_sliceableModel, i->second.first);
1022 } 1024 }
1023 } 1025 }
1024 if (!replaced) emit sliceableModelReplaced(m_sliceableModel, 0); 1026 if (!replaced) emit sliceableModelReplaced(m_sliceableModel, 0);
1025 } 1027 }
1026 1028
1027 delete m_fftModels[v].first; 1029 delete m_fftModels[view].first;
1028 m_fftModels.erase(v); 1030 m_fftModels.erase(view);
1029 1031
1030 delete m_peakCaches[v]; 1032 delete m_peakCaches[view];
1031 m_peakCaches.erase(v); 1033 m_peakCaches.erase(view);
1032 } 1034 }
1033 1035
1034 } else { 1036 } else {
1035 1037
1036 Layer::setLayerDormant(v, false); 1038 Layer::setLayerDormant(v, false);
1179 1181
1180 m_drawBuffer = QImage(); 1182 m_drawBuffer = QImage();
1181 } 1183 }
1182 1184
1183 unsigned char 1185 unsigned char
1184 SpectrogramLayer::getDisplayValue(View *v, double input) const 1186 SpectrogramLayer::getDisplayValue(LayerGeometryProvider *v, double input) const
1185 { 1187 {
1186 int value; 1188 int value;
1187 1189
1188 double min = 0.0; 1190 double min = 0.0;
1189 double max = 1.0; 1191 double max = 1.0;
1292 1294
1293 return maxf; 1295 return maxf;
1294 } 1296 }
1295 1297
1296 bool 1298 bool
1297 SpectrogramLayer::getYBinRange(View *v, int y, double &q0, double &q1) const 1299 SpectrogramLayer::getYBinRange(LayerGeometryProvider *v, int y, double &q0, double &q1) const
1298 { 1300 {
1299 Profiler profiler("SpectrogramLayer::getYBinRange"); 1301 Profiler profiler("SpectrogramLayer::getYBinRange");
1300 1302
1301 int h = v->height(); 1303 int h = v->getPaintHeight();
1302 if (y < 0 || y >= h) return false; 1304 if (y < 0 || y >= h) return false;
1303 1305
1304 sv_samplerate_t sr = m_model->getSampleRate(); 1306 sv_samplerate_t sr = m_model->getSampleRate();
1305 double minf = getEffectiveMinFrequency(); 1307 double minf = getEffectiveMinFrequency();
1306 double maxf = getEffectiveMaxFrequency(); 1308 double maxf = getEffectiveMaxFrequency();
1318 1320
1319 return true; 1321 return true;
1320 } 1322 }
1321 1323
1322 bool 1324 bool
1323 SpectrogramLayer::getSmoothedYBinRange(View *v, int y, double &q0, double &q1) const 1325 SpectrogramLayer::getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &q0, double &q1) const
1324 { 1326 {
1325 Profiler profiler("SpectrogramLayer::getSmoothedYBinRange"); 1327 Profiler profiler("SpectrogramLayer::getSmoothedYBinRange");
1326 1328
1327 int h = v->height(); 1329 int h = v->getPaintHeight();
1328 if (y < 0 || y >= h) return false; 1330 if (y < 0 || y >= h) return false;
1329 1331
1330 sv_samplerate_t sr = m_model->getSampleRate(); 1332 sv_samplerate_t sr = m_model->getSampleRate();
1331 double minf = getEffectiveMinFrequency(); 1333 double minf = getEffectiveMinFrequency();
1332 double maxf = getEffectiveMaxFrequency(); 1334 double maxf = getEffectiveMaxFrequency();
1344 1346
1345 return true; 1347 return true;
1346 } 1348 }
1347 1349
1348 bool 1350 bool
1349 SpectrogramLayer::getXBinRange(View *v, int x, double &s0, double &s1) const 1351 SpectrogramLayer::getXBinRange(LayerGeometryProvider *v, int x, double &s0, double &s1) const
1350 { 1352 {
1351 sv_frame_t modelStart = m_model->getStartFrame(); 1353 sv_frame_t modelStart = m_model->getStartFrame();
1352 sv_frame_t modelEnd = m_model->getEndFrame(); 1354 sv_frame_t modelEnd = m_model->getEndFrame();
1353 1355
1354 // Each pixel column covers an exact range of sample frames: 1356 // Each pixel column covers an exact range of sample frames:
1368 1370
1369 return true; 1371 return true;
1370 } 1372 }
1371 1373
1372 bool 1374 bool
1373 SpectrogramLayer::getXBinSourceRange(View *v, int x, RealTime &min, RealTime &max) const 1375 SpectrogramLayer::getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &min, RealTime &max) const
1374 { 1376 {
1375 double s0 = 0, s1 = 0; 1377 double s0 = 0, s1 = 0;
1376 if (!getXBinRange(v, x, s0, s1)) return false; 1378 if (!getXBinRange(v, x, s0, s1)) return false;
1377 1379
1378 int s0i = int(s0 + 0.001); 1380 int s0i = int(s0 + 0.001);
1387 max = RealTime::frame2RealTime(w1, m_model->getSampleRate()); 1389 max = RealTime::frame2RealTime(w1, m_model->getSampleRate());
1388 return true; 1390 return true;
1389 } 1391 }
1390 1392
1391 bool 1393 bool
1392 SpectrogramLayer::getYBinSourceRange(View *v, int y, double &freqMin, double &freqMax) 1394 SpectrogramLayer::getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax)
1393 const 1395 const
1394 { 1396 {
1395 double q0 = 0, q1 = 0; 1397 double q0 = 0, q1 = 0;
1396 if (!getYBinRange(v, y, q0, q1)) return false; 1398 if (!getYBinRange(v, y, q0, q1)) return false;
1397 1399
1406 } 1408 }
1407 return true; 1409 return true;
1408 } 1410 }
1409 1411
1410 bool 1412 bool
1411 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, 1413 SpectrogramLayer::getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y,
1412 double &freqMin, double &freqMax, 1414 double &freqMin, double &freqMax,
1413 double &adjFreqMin, double &adjFreqMax) 1415 double &adjFreqMin, double &adjFreqMax)
1414 const 1416 const
1415 { 1417 {
1416 if (!m_model || !m_model->isOK() || !m_model->isReady()) { 1418 if (!m_model || !m_model->isOK() || !m_model->isReady()) {
1473 1475
1474 return haveAdj; 1476 return haveAdj;
1475 } 1477 }
1476 1478
1477 bool 1479 bool
1478 SpectrogramLayer::getXYBinSourceRange(View *v, int x, int y, 1480 SpectrogramLayer::getXYBinSourceRange(LayerGeometryProvider *v, int x, int y,
1479 double &min, double &max, 1481 double &min, double &max,
1480 double &phaseMin, double &phaseMax) const 1482 double &phaseMin, double &phaseMax) const
1481 { 1483 {
1482 if (!m_model || !m_model->isOK() || !m_model->isReady()) { 1484 if (!m_model || !m_model->isOK() || !m_model->isReady()) {
1483 return false; 1485 return false;
1542 1544
1543 return rv; 1545 return rv;
1544 } 1546 }
1545 1547
1546 int 1548 int
1547 SpectrogramLayer::getZeroPadLevel(const View *v) const 1549 SpectrogramLayer::getZeroPadLevel(const LayerGeometryProvider *v) const
1548 { 1550 {
1549 //!!! tidy all this stuff 1551 //!!! tidy all this stuff
1550 1552
1551 if (m_binDisplay != AllBins) return 0; 1553 if (m_binDisplay != AllBins) return 0;
1552 1554
1572 if (minbin < 1) minbin = 1; 1574 if (minbin < 1) minbin = 1;
1573 if (minbin >= maxbin) minbin = maxbin - 1; 1575 if (minbin >= maxbin) minbin = maxbin - 1;
1574 } 1576 }
1575 1577
1576 double perPixel = 1578 double perPixel =
1577 double(v->height()) / 1579 double(v->getPaintHeight()) /
1578 double((maxbin - minbin) / (m_zeroPadLevel + 1)); 1580 double((maxbin - minbin) / (m_zeroPadLevel + 1));
1579 1581
1580 if (perPixel > 2.8) { 1582 if (perPixel > 2.8) {
1581 return 3; // 4x oversampling 1583 return 3; // 4x oversampling
1582 } else if (perPixel > 1.5) { 1584 } else if (perPixel > 1.5) {
1585 return 0; // 1x 1587 return 0; // 1x
1586 } 1588 }
1587 } 1589 }
1588 1590
1589 int 1591 int
1590 SpectrogramLayer::getFFTSize(const View *v) const 1592 SpectrogramLayer::getFFTSize(const LayerGeometryProvider *v) const
1591 { 1593 {
1592 return m_fftSize * (getZeroPadLevel(v) + 1); 1594 return m_fftSize * (getZeroPadLevel(v) + 1);
1593 } 1595 }
1594 1596
1595 FFTModel * 1597 FFTModel *
1596 SpectrogramLayer::getFFTModel(const View *v) const 1598 SpectrogramLayer::getFFTModel(const LayerGeometryProvider *v) const
1597 { 1599 {
1598 if (!m_model) return 0; 1600 if (!m_model) return 0;
1599 1601
1600 int fftSize = getFFTSize(v); 1602 int fftSize = getFFTSize(v);
1601 1603
1602 if (m_fftModels.find(v) != m_fftModels.end()) { 1604 const View *view = v->getView();
1603 if (m_fftModels[v].first == 0) { 1605
1606 if (m_fftModels.find(view) != m_fftModels.end()) {
1607 if (m_fftModels[view].first == 0) {
1604 #ifdef DEBUG_SPECTROGRAM_REPAINT 1608 #ifdef DEBUG_SPECTROGRAM_REPAINT
1605 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found null model" << endl; 1609 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found null model" << endl;
1606 #endif 1610 #endif
1607 return 0; 1611 return 0;
1608 } 1612 }
1609 if (m_fftModels[v].first->getHeight() != fftSize / 2 + 1) { 1613 if (m_fftModels[view].first->getHeight() != fftSize / 2 + 1) {
1610 #ifdef DEBUG_SPECTROGRAM_REPAINT 1614 #ifdef DEBUG_SPECTROGRAM_REPAINT
1611 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a model with the wrong height (" << m_fftModels[v].first->getHeight() << ", wanted " << (fftSize / 2 + 1) << ")" << endl; 1615 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a model with the wrong height (" << m_fftModels[view].first->getHeight() << ", wanted " << (fftSize / 2 + 1) << ")" << endl;
1612 #endif 1616 #endif
1613 delete m_fftModels[v].first; 1617 delete m_fftModels[view].first;
1614 m_fftModels.erase(v); 1618 m_fftModels.erase(view);
1615 delete m_peakCaches[v]; 1619 delete m_peakCaches[view];
1616 m_peakCaches.erase(v); 1620 m_peakCaches.erase(view);
1617 } else { 1621 } else {
1618 #ifdef DEBUG_SPECTROGRAM_REPAINT 1622 #ifdef DEBUG_SPECTROGRAM_REPAINT
1619 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[v].first->getHeight() << endl; 1623 SVDEBUG << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[view].first->getHeight() << endl;
1620 #endif 1624 #endif
1621 return m_fftModels[v].first; 1625 return m_fftModels[view].first;
1622 } 1626 }
1623 } 1627 }
1624 1628
1625 if (m_fftModels.find(v) == m_fftModels.end()) { 1629 if (m_fftModels.find(view) == m_fftModels.end()) {
1626 1630
1627 FFTModel *model = new FFTModel(m_model, 1631 FFTModel *model = new FFTModel(m_model,
1628 m_channel, 1632 m_channel,
1629 m_windowType, 1633 m_windowType,
1630 m_windowSize, 1634 m_windowSize,
1635 QMessageBox::critical 1639 QMessageBox::critical
1636 (0, tr("FFT cache failed"), 1640 (0, tr("FFT cache failed"),
1637 tr("Failed to create the FFT model for this spectrogram.\n" 1641 tr("Failed to create the FFT model for this spectrogram.\n"
1638 "There may be insufficient memory or disc space to continue.")); 1642 "There may be insufficient memory or disc space to continue."));
1639 delete model; 1643 delete model;
1640 m_fftModels[v] = FFTFillPair(0, 0); 1644 m_fftModels[view] = FFTFillPair(0, 0);
1641 return 0; 1645 return 0;
1642 } 1646 }
1643 1647
1644 if (!m_sliceableModel) { 1648 if (!m_sliceableModel) {
1645 #ifdef DEBUG_SPECTROGRAM 1649 #ifdef DEBUG_SPECTROGRAM
1647 #endif 1651 #endif
1648 ((SpectrogramLayer *)this)->sliceableModelReplaced(0, model); 1652 ((SpectrogramLayer *)this)->sliceableModelReplaced(0, model);
1649 m_sliceableModel = model; 1653 m_sliceableModel = model;
1650 } 1654 }
1651 1655
1652 m_fftModels[v] = FFTFillPair(model, 0); 1656 m_fftModels[view] = FFTFillPair(model, 0);
1653 1657
1654 delete m_updateTimer; 1658 delete m_updateTimer;
1655 m_updateTimer = new QTimer((SpectrogramLayer *)this); 1659 m_updateTimer = new QTimer((SpectrogramLayer *)this);
1656 connect(m_updateTimer, SIGNAL(timeout()), 1660 connect(m_updateTimer, SIGNAL(timeout()),
1657 this, SLOT(fillTimerTimedOut())); 1661 this, SLOT(fillTimerTimedOut()));
1658 m_updateTimer->start(200); 1662 m_updateTimer->start(200);
1659 } 1663 }
1660 1664
1661 return m_fftModels[v].first; 1665 return m_fftModels[view].first;
1662 } 1666 }
1663 1667
1664 Dense3DModelPeakCache * 1668 Dense3DModelPeakCache *
1665 SpectrogramLayer::getPeakCache(const View *v) const 1669 SpectrogramLayer::getPeakCache(const LayerGeometryProvider *v) const
1666 { 1670 {
1667 if (!m_peakCaches[v]) { 1671 const View *view = v->getView();
1672 if (!m_peakCaches[view]) {
1668 FFTModel *f = getFFTModel(v); 1673 FFTModel *f = getFFTModel(v);
1669 if (!f) return 0; 1674 if (!f) return 0;
1670 m_peakCaches[v] = new Dense3DModelPeakCache(f, 8); 1675 m_peakCaches[view] = new Dense3DModelPeakCache(f, 8);
1671 } 1676 }
1672 return m_peakCaches[v]; 1677 return m_peakCaches[view];
1673 } 1678 }
1674 1679
1675 const Model * 1680 const Model *
1676 SpectrogramLayer::getSliceableModel() const 1681 SpectrogramLayer::getSliceableModel() const
1677 { 1682 {
1712 *i = MagnitudeRange(); 1717 *i = MagnitudeRange();
1713 } 1718 }
1714 } 1719 }
1715 1720
1716 bool 1721 bool
1717 SpectrogramLayer::updateViewMagnitudes(View *v) const 1722 SpectrogramLayer::updateViewMagnitudes(LayerGeometryProvider *v) const
1718 { 1723 {
1719 MagnitudeRange mag; 1724 MagnitudeRange mag;
1720 1725
1721 int x0 = 0, x1 = v->width(); 1726 int x0 = 0, x1 = v->getPaintWidth();
1722 double s00 = 0, s01 = 0, s10 = 0, s11 = 0; 1727 double s00 = 0, s01 = 0, s10 = 0, s11 = 0;
1723 1728
1724 if (!getXBinRange(v, x0, s00, s01)) { 1729 if (!getXBinRange(v, x0, s00, s01)) {
1725 s00 = s01 = double(m_model->getStartFrame()) / getWindowIncrement(); 1730 s00 = s01 = double(m_model->getStartFrame()) / getWindowIncrement();
1726 } 1731 }
1760 { 1765 {
1761 m_synchronous = synchronous; 1766 m_synchronous = synchronous;
1762 } 1767 }
1763 1768
1764 void 1769 void
1765 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const 1770 SpectrogramLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
1766 { 1771 {
1767 // What a lovely, old-fashioned function this is. 1772 // What a lovely, old-fashioned function this is.
1768 // It's practically FORTRAN 77 in its clarity and linearity. 1773 // It's practically FORTRAN 77 in its clarity and linearity.
1769 1774
1770 Profiler profiler("SpectrogramLayer::paint", false); 1775 Profiler profiler("SpectrogramLayer::paint", false);
1800 if (!fft) { 1805 if (!fft) {
1801 cerr << "ERROR: SpectrogramLayer::paint(): No FFT model, returning" << endl; 1806 cerr << "ERROR: SpectrogramLayer::paint(): No FFT model, returning" << endl;
1802 return; 1807 return;
1803 } 1808 }
1804 */ 1809 */
1805 ImageCache &cache = m_imageCaches[v]; 1810
1811 const View *view = v->getView();
1812
1813 ImageCache &cache = m_imageCaches[view];
1806 1814
1807 #ifdef DEBUG_SPECTROGRAM_REPAINT 1815 #ifdef DEBUG_SPECTROGRAM_REPAINT
1808 SVDEBUG << "SpectrogramLayer::paint(): image cache valid area " << cache. 1816 SVDEBUG << "SpectrogramLayer::paint(): image cache valid area " << cache.
1809 1817
1810 validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << endl; 1818 validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << endl;
1816 #endif 1824 #endif
1817 1825
1818 int zoomLevel = v->getZoomLevel(); 1826 int zoomLevel = v->getZoomLevel();
1819 1827
1820 int x0 = 0; 1828 int x0 = 0;
1821 int x1 = v->width(); 1829 int x1 = v->getPaintWidth();
1822 1830
1823 bool recreateWholeImageCache = true; 1831 bool recreateWholeImageCache = true;
1824 1832
1825 x0 = rect.left(); 1833 x0 = rect.left();
1826 x1 = rect.right() + 1; 1834 x1 = rect.right() + 1;
1833 1841
1834 int cw = cache.image.width(); 1842 int cw = cache.image.width();
1835 int ch = cache.image.height(); 1843 int ch = cache.image.height();
1836 1844
1837 if (int(cache.zoomLevel) == zoomLevel && 1845 if (int(cache.zoomLevel) == zoomLevel &&
1838 cw == v->width() && 1846 cw == v->getPaintWidth() &&
1839 ch == v->height()) { 1847 ch == v->getPaintHeight()) {
1840 1848
1841 if (v->getXForFrame(cache.startFrame) == 1849 if (v->getXForFrame(cache.startFrame) ==
1842 v->getXForFrame(startFrame) && 1850 v->getXForFrame(startFrame) &&
1843 cache.validArea.x() <= x0 && 1851 cache.validArea.x() <= x0 &&
1844 cache.validArea.x() + cache.validArea.width() >= x1) { 1852 cache.validArea.x() + cache.validArea.width() >= x1) {
1940 cerr << "SpectrogramLayer: image cache useless" << endl; 1948 cerr << "SpectrogramLayer: image cache useless" << endl;
1941 if (int(cache.zoomLevel) != zoomLevel) { 1949 if (int(cache.zoomLevel) != zoomLevel) {
1942 cerr << "(cache zoomLevel " << cache.zoomLevel 1950 cerr << "(cache zoomLevel " << cache.zoomLevel
1943 << " != " << zoomLevel << ")" << endl; 1951 << " != " << zoomLevel << ")" << endl;
1944 } 1952 }
1945 if (cw != v->width()) { 1953 if (cw != v->getPaintWidth()) {
1946 cerr << "(cache width " << cw 1954 cerr << "(cache width " << cw
1947 << " != " << v->width(); 1955 << " != " << v->getPaintWidth();
1948 } 1956 }
1949 if (ch != v->height()) { 1957 if (ch != v->getPaintHeight()) {
1950 cerr << "(cache height " << ch 1958 cerr << "(cache height " << ch
1951 << " != " << v->height(); 1959 << " != " << v->getPaintHeight();
1952 } 1960 }
1953 #endif 1961 #endif
1954 cache.validArea = QRect(); 1962 cache.validArea = QRect();
1955 // recreateWholeImageCache = true; 1963 // recreateWholeImageCache = true;
1956 } 1964 }
1970 #endif 1978 #endif
1971 } 1979 }
1972 1980
1973 if (recreateWholeImageCache) { 1981 if (recreateWholeImageCache) {
1974 x0 = 0; 1982 x0 = 0;
1975 x1 = v->width(); 1983 x1 = v->getPaintWidth();
1976 } 1984 }
1977 1985
1978 struct timeval tv; 1986 struct timeval tv;
1979 (void)gettimeofday(&tv, 0); 1987 (void)gettimeofday(&tv, 0);
1980 RealTime mainPaintStart = RealTime::fromTimeval(tv); 1988 RealTime mainPaintStart = RealTime::fromTimeval(tv);
2014 // Smaller heights can be used when painting direct from cache 2022 // Smaller heights can be used when painting direct from cache
2015 // (further up in this function), but we want to ensure the cache 2023 // (further up in this function), but we want to ensure the cache
2016 // is coherent without having to worry about vertical matching of 2024 // is coherent without having to worry about vertical matching of
2017 // required and valid areas as well as horizontal. 2025 // required and valid areas as well as horizontal.
2018 2026
2019 int h = v->height(); 2027 int h = v->getPaintHeight();
2020 2028
2021 if (cache.validArea.width() > 0) { 2029 if (cache.validArea.width() > 0) {
2022 2030
2023 // If part of the cache is known to be valid, select a strip 2031 // If part of the cache is known to be valid, select a strip
2024 // immediately to left or right of the valid part 2032 // immediately to left or right of the valid part
2321 2329
2322 Profiler profiler2("SpectrogramLayer::paint: draw image"); 2330 Profiler profiler2("SpectrogramLayer::paint: draw image");
2323 2331
2324 if (recreateWholeImageCache) { 2332 if (recreateWholeImageCache) {
2325 #ifdef DEBUG_SPECTROGRAM_REPAINT 2333 #ifdef DEBUG_SPECTROGRAM_REPAINT
2326 SVDEBUG << "Recreating image cache: width = " << v->width() 2334 SVDEBUG << "Recreating image cache: width = " << v->getPaintWidth()
2327 << ", height = " << h << endl; 2335 << ", height = " << h << endl;
2328 #endif 2336 #endif
2329 cache.image = QImage(v->width(), h, QImage::Format_ARGB32_Premultiplied); 2337 cache.image = QImage(v->getPaintWidth(), h, QImage::Format_ARGB32_Premultiplied);
2330 } 2338 }
2331 2339
2332 if (w > 0) { 2340 if (w > 0) {
2333 #ifdef DEBUG_SPECTROGRAM_REPAINT 2341 #ifdef DEBUG_SPECTROGRAM_REPAINT
2334 SVDEBUG << "Painting " << w << "x" << h 2342 SVDEBUG << "Painting " << w << "x" << h
2400 if (cache.validArea.x() > 0) { 2408 if (cache.validArea.x() > 0) {
2401 #ifdef DEBUG_SPECTROGRAM_REPAINT 2409 #ifdef DEBUG_SPECTROGRAM_REPAINT
2402 SVDEBUG << "SpectrogramLayer::paint() updating left (0, " 2410 SVDEBUG << "SpectrogramLayer::paint() updating left (0, "
2403 << cache.validArea.x() << ")" << endl; 2411 << cache.validArea.x() << ")" << endl;
2404 #endif 2412 #endif
2405 v->update(0, 0, cache.validArea.x(), h); 2413 v->getView()->update(0, 0, cache.validArea.x(), h);
2406 } 2414 }
2407 2415
2408 if (cache.validArea.x() + cache.validArea.width() < 2416 if (cache.validArea.x() + cache.validArea.width() <
2409 cache.image.width()) { 2417 cache.image.width()) {
2410 #ifdef DEBUG_SPECTROGRAM_REPAINT 2418 #ifdef DEBUG_SPECTROGRAM_REPAINT
2413 << ", " 2421 << ", "
2414 << cache.image.width() - (cache.validArea.x() + 2422 << cache.image.width() - (cache.validArea.x() +
2415 cache.validArea.width()) 2423 cache.validArea.width())
2416 << ")" << endl; 2424 << ")" << endl;
2417 #endif 2425 #endif
2418 v->update(cache.validArea.x() + cache.validArea.width(), 2426 v->getView()->update(cache.validArea.x() + cache.validArea.width(),
2419 0, 2427 0,
2420 cache.image.width() - (cache.validArea.x() + 2428 cache.image.width() - (cache.validArea.x() +
2421 cache.validArea.width()), 2429 cache.validArea.width()),
2422 h); 2430 h);
2423 } 2431 }
2424 } else { 2432 } else {
2425 // overallMagChanged 2433 // overallMagChanged
2426 cerr << "\noverallMagChanged - updating all\n" << endl; 2434 cerr << "\noverallMagChanged - updating all\n" << endl;
2427 cache.validArea = QRect(); 2435 cache.validArea = QRect();
2428 v->update(); 2436 v->getView()->update();
2429 } 2437 }
2430 } 2438 }
2431 2439
2432 illuminateLocalFeatures(v, paint); 2440 illuminateLocalFeatures(v, paint);
2433 2441
2441 m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart; 2449 m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart;
2442 } 2450 }
2443 } 2451 }
2444 2452
2445 bool 2453 bool
2446 SpectrogramLayer::paintDrawBufferPeakFrequencies(View *v, 2454 SpectrogramLayer::paintDrawBufferPeakFrequencies(LayerGeometryProvider *v,
2447 int w, 2455 int w,
2448 int h, 2456 int h,
2449 const vector<int> &binforx, 2457 const vector<int> &binforx,
2450 int minbin, 2458 int minbin,
2451 int maxbin, 2459 int maxbin,
2569 2577
2570 return true; 2578 return true;
2571 } 2579 }
2572 2580
2573 bool 2581 bool
2574 SpectrogramLayer::paintDrawBuffer(View *v, 2582 SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v,
2575 int w, 2583 int w,
2576 int h, 2584 int h,
2577 const vector<int> &binforx, 2585 const vector<int> &binforx,
2578 const vector<double> &binfory, 2586 const vector<double> &binfory,
2579 bool usePeaksCache, 2587 bool usePeaksCache,
2810 2818
2811 return true; 2819 return true;
2812 } 2820 }
2813 2821
2814 void 2822 void
2815 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const 2823 SpectrogramLayer::illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &paint) const
2816 { 2824 {
2817 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); 2825 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures");
2818 2826
2819 QPoint localPos; 2827 QPoint localPos;
2820 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) { 2828 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) {
2849 paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1); 2857 paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1);
2850 } 2858 }
2851 } 2859 }
2852 2860
2853 double 2861 double
2854 SpectrogramLayer::getYForFrequency(const View *v, double frequency) const 2862 SpectrogramLayer::getYForFrequency(const LayerGeometryProvider *v, double frequency) const
2855 { 2863 {
2856 return v->getYForFrequency(frequency, 2864 return v->getYForFrequency(frequency,
2857 getEffectiveMinFrequency(), 2865 getEffectiveMinFrequency(),
2858 getEffectiveMaxFrequency(), 2866 getEffectiveMaxFrequency(),
2859 m_frequencyScale == LogFrequencyScale); 2867 m_frequencyScale == LogFrequencyScale);
2860 } 2868 }
2861 2869
2862 double 2870 double
2863 SpectrogramLayer::getFrequencyForY(const View *v, int y) const 2871 SpectrogramLayer::getFrequencyForY(const LayerGeometryProvider *v, int y) const
2864 { 2872 {
2865 return v->getFrequencyForY(y, 2873 return v->getFrequencyForY(y,
2866 getEffectiveMinFrequency(), 2874 getEffectiveMinFrequency(),
2867 getEffectiveMaxFrequency(), 2875 getEffectiveMaxFrequency(),
2868 m_frequencyScale == LogFrequencyScale); 2876 m_frequencyScale == LogFrequencyScale);
2869 } 2877 }
2870 2878
2871 int 2879 int
2872 SpectrogramLayer::getCompletion(View *v) const 2880 SpectrogramLayer::getCompletion(LayerGeometryProvider *v) const
2873 { 2881 {
2874 if (m_updateTimer == 0) return 100; 2882 if (m_updateTimer == 0) return 100;
2875 if (m_fftModels.find(v) == m_fftModels.end()) return 100; 2883
2876 2884 const View *view = v->getView();
2877 int completion = m_fftModels[v].first->getCompletion(); 2885
2886 if (m_fftModels.find(view) == m_fftModels.end()) return 100;
2887
2888 int completion = m_fftModels[view].first->getCompletion();
2878 #ifdef DEBUG_SPECTROGRAM_REPAINT 2889 #ifdef DEBUG_SPECTROGRAM_REPAINT
2879 SVDEBUG << "SpectrogramLayer::getCompletion: completion = " << completion << endl; 2890 SVDEBUG << "SpectrogramLayer::getCompletion: completion = " << completion << endl;
2880 #endif 2891 #endif
2881 return completion; 2892 return completion;
2882 } 2893 }
2883 2894
2884 QString 2895 QString
2885 SpectrogramLayer::getError(View *v) const 2896 SpectrogramLayer::getError(LayerGeometryProvider *v) const
2886 { 2897 {
2887 if (m_fftModels.find(v) == m_fftModels.end()) return ""; 2898 const View *view = v->getView();
2888 return m_fftModels[v].first->getError(); 2899 if (m_fftModels.find(view) == m_fftModels.end()) return "";
2900 return m_fftModels[view].first->getError();
2889 } 2901 }
2890 2902
2891 bool 2903 bool
2892 SpectrogramLayer::getValueExtents(double &min, double &max, 2904 SpectrogramLayer::getValueExtents(double &min, double &max,
2893 bool &logarithmic, QString &unit) const 2905 bool &logarithmic, QString &unit) const
2944 2956
2945 return true; 2957 return true;
2946 } 2958 }
2947 2959
2948 bool 2960 bool
2949 SpectrogramLayer::getYScaleValue(const View *v, int y, 2961 SpectrogramLayer::getYScaleValue(const LayerGeometryProvider *v, int y,
2950 double &value, QString &unit) const 2962 double &value, QString &unit) const
2951 { 2963 {
2952 value = getFrequencyForY(v, y); 2964 value = getFrequencyForY(v, y);
2953 unit = "Hz"; 2965 unit = "Hz";
2954 return true; 2966 return true;
2955 } 2967 }
2956 2968
2957 bool 2969 bool
2958 SpectrogramLayer::snapToFeatureFrame(View *, 2970 SpectrogramLayer::snapToFeatureFrame(LayerGeometryProvider *,
2959 sv_frame_t &frame, 2971 sv_frame_t &frame,
2960 int &resolution, 2972 int &resolution,
2961 SnapType snap) const 2973 SnapType snap) const
2962 { 2974 {
2963 resolution = getWindowIncrement(); 2975 resolution = getWindowIncrement();
2976 2988
2977 return true; 2989 return true;
2978 } 2990 }
2979 2991
2980 void 2992 void
2981 SpectrogramLayer::measureDoubleClick(View *v, QMouseEvent *e) 2993 SpectrogramLayer::measureDoubleClick(LayerGeometryProvider *v, QMouseEvent *e)
2982 { 2994 {
2983 ImageCache &cache = m_imageCaches[v]; 2995 const View *view = v->getView();
2996 ImageCache &cache = m_imageCaches[view];
2984 2997
2985 cerr << "cache width: " << cache.image.width() << ", height: " 2998 cerr << "cache width: " << cache.image.width() << ", height: "
2986 << cache.image.height() << endl; 2999 << cache.image.height() << endl;
2987 3000
2988 QImage image = cache.image; 3001 QImage image = cache.image;
2989 3002
2990 ImageRegionFinder finder; 3003 ImageRegionFinder finder;
2991 QRect rect = finder.findRegionExtents(&image, e->pos()); 3004 QRect rect = finder.findRegionExtents(&image, e->pos());
2996 (new AddMeasurementRectCommand(this, mr)); 3009 (new AddMeasurementRectCommand(this, mr));
2997 } 3010 }
2998 } 3011 }
2999 3012
3000 bool 3013 bool
3001 SpectrogramLayer::getCrosshairExtents(View *v, QPainter &paint, 3014 SpectrogramLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint,
3002 QPoint cursorPos, 3015 QPoint cursorPos,
3003 std::vector<QRect> &extents) const 3016 std::vector<QRect> &extents) const
3004 { 3017 {
3005 QRect vertical(cursorPos.x() - 12, 0, 12, v->height()); 3018 QRect vertical(cursorPos.x() - 12, 0, 12, v->getPaintHeight());
3006 extents.push_back(vertical); 3019 extents.push_back(vertical);
3007 3020
3008 QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1); 3021 QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1);
3009 extents.push_back(horizontal); 3022 extents.push_back(horizontal);
3010 3023
3019 paint.fontMetrics().width("C#10+50c") + 2, 3032 paint.fontMetrics().width("C#10+50c") + 2,
3020 paint.fontMetrics().height()); 3033 paint.fontMetrics().height());
3021 extents.push_back(pitch); 3034 extents.push_back(pitch);
3022 3035
3023 QRect rt(cursorPos.x(), 3036 QRect rt(cursorPos.x(),
3024 v->height() - paint.fontMetrics().height() - 2, 3037 v->getPaintHeight() - paint.fontMetrics().height() - 2,
3025 paint.fontMetrics().width("1234.567 s"), 3038 paint.fontMetrics().width("1234.567 s"),
3026 paint.fontMetrics().height()); 3039 paint.fontMetrics().height());
3027 extents.push_back(rt); 3040 extents.push_back(rt);
3028 3041
3029 int w(paint.fontMetrics().width("1234567890") + 2); 3042 int w(paint.fontMetrics().width("1234567890") + 2);
3030 QRect frame(cursorPos.x() - w - 2, 3043 QRect frame(cursorPos.x() - w - 2,
3031 v->height() - paint.fontMetrics().height() - 2, 3044 v->getPaintHeight() - paint.fontMetrics().height() - 2,
3032 w, 3045 w,
3033 paint.fontMetrics().height()); 3046 paint.fontMetrics().height());
3034 extents.push_back(frame); 3047 extents.push_back(frame);
3035 3048
3036 return true; 3049 return true;
3037 } 3050 }
3038 3051
3039 void 3052 void
3040 SpectrogramLayer::paintCrosshairs(View *v, QPainter &paint, 3053 SpectrogramLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint,
3041 QPoint cursorPos) const 3054 QPoint cursorPos) const
3042 { 3055 {
3043 paint.save(); 3056 paint.save();
3044 3057
3045 int sw = getVerticalScaleWidth(v, m_haveDetailedScale, paint); 3058 int sw = getVerticalScaleWidth(v, m_haveDetailedScale, paint);
3050 paint.setFont(fn); 3063 paint.setFont(fn);
3051 } 3064 }
3052 paint.setPen(m_crosshairColour); 3065 paint.setPen(m_crosshairColour);
3053 3066
3054 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); 3067 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y());
3055 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->height()); 3068 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->getPaintHeight());
3056 3069
3057 double fundamental = getFrequencyForY(v, cursorPos.y()); 3070 double fundamental = getFrequencyForY(v, cursorPos.y());
3058 3071
3059 v->drawVisibleText(paint, 3072 v->drawVisibleText(paint,
3060 sw + 2, 3073 sw + 2,
3075 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate()); 3088 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate());
3076 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); 3089 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str());
3077 QString frameLabel = QString("%1").arg(frame); 3090 QString frameLabel = QString("%1").arg(frame);
3078 v->drawVisibleText(paint, 3091 v->drawVisibleText(paint,
3079 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, 3092 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2,
3080 v->height() - 2, 3093 v->getPaintHeight() - 2,
3081 frameLabel, 3094 frameLabel,
3082 View::OutlinedText); 3095 View::OutlinedText);
3083 v->drawVisibleText(paint, 3096 v->drawVisibleText(paint,
3084 cursorPos.x() + 2, 3097 cursorPos.x() + 2,
3085 v->height() - 2, 3098 v->getPaintHeight() - 2,
3086 rtLabel, 3099 rtLabel,
3087 View::OutlinedText); 3100 View::OutlinedText);
3088 3101
3089 int harmonic = 2; 3102 int harmonic = 2;
3090 3103
3091 while (harmonic < 100) { 3104 while (harmonic < 100) {
3092 3105
3093 int hy = int(lrint(getYForFrequency(v, fundamental * harmonic))); 3106 int hy = int(lrint(getYForFrequency(v, fundamental * harmonic)));
3094 if (hy < 0 || hy > v->height()) break; 3107 if (hy < 0 || hy > v->getPaintHeight()) break;
3095 3108
3096 int len = 7; 3109 int len = 7;
3097 3110
3098 if (harmonic % 2 == 0) { 3111 if (harmonic % 2 == 0) {
3099 if (harmonic % 4 == 0) { 3112 if (harmonic % 4 == 0) {
3113 3126
3114 paint.restore(); 3127 paint.restore();
3115 } 3128 }
3116 3129
3117 QString 3130 QString
3118 SpectrogramLayer::getFeatureDescription(View *v, QPoint &pos) const 3131 SpectrogramLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
3119 { 3132 {
3120 int x = pos.x(); 3133 int x = pos.x();
3121 int y = pos.y(); 3134 int y = pos.y();
3122 3135
3123 if (!m_model || !m_model->isOK()) return ""; 3136 if (!m_model || !m_model->isOK()) return "";
3235 3248
3236 return cw; 3249 return cw;
3237 } 3250 }
3238 3251
3239 int 3252 int
3240 SpectrogramLayer::getVerticalScaleWidth(View *, bool detailed, QPainter &paint) const 3253 SpectrogramLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &paint) const
3241 { 3254 {
3242 if (!m_model || !m_model->isOK()) return 0; 3255 if (!m_model || !m_model->isOK()) return 0;
3243 3256
3244 int cw = 0; 3257 int cw = 0;
3245 if (detailed) cw = getColourScaleWidth(paint); 3258 if (detailed) cw = getColourScaleWidth(paint);
3256 3269
3257 return cw + tickw + tw + 13; 3270 return cw + tickw + tw + 13;
3258 } 3271 }
3259 3272
3260 void 3273 void
3261 SpectrogramLayer::paintVerticalScale(View *v, bool detailed, QPainter &paint, QRect rect) const 3274 SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const
3262 { 3275 {
3263 if (!m_model || !m_model->isOK()) { 3276 if (!m_model || !m_model->isOK()) {
3264 return; 3277 return;
3265 } 3278 }
3266 3279
3370 3383
3371 paint.drawLine(cw + 7, 0, cw + 7, h); 3384 paint.drawLine(cw + 7, 0, cw + 7, h);
3372 3385
3373 int bin = -1; 3386 int bin = -1;
3374 3387
3375 for (int y = 0; y < v->height(); ++y) { 3388 for (int y = 0; y < v->getPaintHeight(); ++y) {
3376 3389
3377 double q0, q1; 3390 double q0, q1;
3378 if (!getYBinRange(v, v->height() - y, q0, q1)) continue; 3391 if (!getYBinRange(v, v->getPaintHeight() - y, q0, q1)) continue;
3379 3392
3380 int vy; 3393 int vy;
3381 3394
3382 if (int(q0) > bin) { 3395 if (int(q0) > bin) {
3383 vy = y; 3396 vy = y;
3587 if (!m_model) return 0; 3600 if (!m_model) return 0;
3588 return new SpectrogramRangeMapper(m_model->getSampleRate(), m_fftSize); 3601 return new SpectrogramRangeMapper(m_model->getSampleRate(), m_fftSize);
3589 } 3602 }
3590 3603
3591 void 3604 void
3592 SpectrogramLayer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const 3605 SpectrogramLayer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const
3593 { 3606 {
3594 int y0 = 0; 3607 int y0 = 0;
3595 if (r.startY > 0.0) y0 = int(getYForFrequency(v, r.startY)); 3608 if (r.startY > 0.0) y0 = int(getYForFrequency(v, r.startY));
3596 3609
3597 int y1 = y0; 3610 int y1 = y0;
3601 3614
3602 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); 3615 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
3603 } 3616 }
3604 3617
3605 void 3618 void
3606 SpectrogramLayer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const 3619 SpectrogramLayer::setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const
3607 { 3620 {
3608 if (start) { 3621 if (start) {
3609 r.startY = getFrequencyForY(v, y); 3622 r.startY = getFrequencyForY(v, y);
3610 r.endY = r.startY; 3623 r.endY = r.startY;
3611 } else { 3624 } else {