Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 1088:c520f90bbf2e spectrogram-minor-refactor
One FFT model per spectrogram (again!) - but we do still need a magnitude range per view, as views could be showing different regions
author | Chris Cannam |
---|---|
date | Tue, 05 Jul 2016 08:58:28 +0100 |
parents | 6d990a24ac1b |
children | c8683d94442a |
comparison
equal
deleted
inserted
replaced
1087:6d990a24ac1b | 1088:c520f90bbf2e |
---|---|
77 m_normalization(ColumnOp::NoNormalization), | 77 m_normalization(ColumnOp::NoNormalization), |
78 m_lastEmittedZoomStep(-1), | 78 m_lastEmittedZoomStep(-1), |
79 m_synchronous(false), | 79 m_synchronous(false), |
80 m_haveDetailedScale(false), | 80 m_haveDetailedScale(false), |
81 m_exiting(false), | 81 m_exiting(false), |
82 m_peakCacheDivisor(8), | 82 m_fftModel(0), |
83 m_sliceableModel(0) | 83 m_peakCache(0), |
84 m_peakCacheDivisor(8) | |
84 { | 85 { |
85 QString colourConfigName = "spectrogram-colour"; | 86 QString colourConfigName = "spectrogram-colour"; |
86 int colourConfigDefault = int(ColourMapper::Green); | 87 int colourConfigDefault = int(ColourMapper::Green); |
87 | 88 |
88 if (config == FullRangeDb) { | 89 if (config == FullRangeDb) { |
127 initialisePalette(); | 128 initialisePalette(); |
128 } | 129 } |
129 | 130 |
130 SpectrogramLayer::~SpectrogramLayer() | 131 SpectrogramLayer::~SpectrogramLayer() |
131 { | 132 { |
132 invalidateFFTModels(); | 133 invalidateFFTModel(); |
133 } | 134 } |
134 | 135 |
135 void | 136 void |
136 SpectrogramLayer::setModel(const DenseTimeValueModel *model) | 137 SpectrogramLayer::setModel(const DenseTimeValueModel *model) |
137 { | 138 { |
138 // cerr << "SpectrogramLayer(" << this << "): setModel(" << model << ")" << endl; | 139 // cerr << "SpectrogramLayer(" << this << "): setModel(" << model << ")" << endl; |
139 | 140 |
140 if (model == m_model) return; | 141 if (model == m_model) return; |
141 | 142 |
142 m_model = model; | 143 m_model = model; |
143 invalidateFFTModels(); | 144 invalidateFFTModel(); |
144 | 145 |
145 if (!m_model || !m_model->isOK()) return; | 146 if (!m_model || !m_model->isOK()) return; |
146 | 147 |
147 connectSignals(m_model); | 148 connectSignals(m_model); |
148 | 149 |
605 { | 606 { |
606 if (m_channel == ch) return; | 607 if (m_channel == ch) return; |
607 | 608 |
608 invalidateImageCaches(); | 609 invalidateImageCaches(); |
609 m_channel = ch; | 610 m_channel = ch; |
610 invalidateFFTModels(); | 611 invalidateFFTModel(); |
611 | 612 |
612 emit layerParametersChanged(); | 613 emit layerParametersChanged(); |
613 } | 614 } |
614 | 615 |
615 int | 616 int |
649 | 650 |
650 invalidateImageCaches(); | 651 invalidateImageCaches(); |
651 | 652 |
652 m_windowSize = ws; | 653 m_windowSize = ws; |
653 | 654 |
654 invalidateFFTModels(); | 655 invalidateFFTModel(); |
655 | 656 |
656 emit layerParametersChanged(); | 657 emit layerParametersChanged(); |
657 } | 658 } |
658 | 659 |
659 int | 660 int |
669 | 670 |
670 invalidateImageCaches(); | 671 invalidateImageCaches(); |
671 | 672 |
672 m_windowHopLevel = v; | 673 m_windowHopLevel = v; |
673 | 674 |
674 invalidateFFTModels(); | 675 invalidateFFTModel(); |
675 | 676 |
676 emit layerParametersChanged(); | 677 emit layerParametersChanged(); |
677 | 678 |
678 // fillCache(); | 679 // fillCache(); |
679 } | 680 } |
691 | 692 |
692 invalidateImageCaches(); | 693 invalidateImageCaches(); |
693 | 694 |
694 m_windowType = w; | 695 m_windowType = w; |
695 | 696 |
696 invalidateFFTModels(); | 697 invalidateFFTModel(); |
697 | 698 |
698 emit layerParametersChanged(); | 699 emit layerParametersChanged(); |
699 } | 700 } |
700 | 701 |
701 WindowType | 702 WindowType |
911 | 912 |
912 invalidateImageCaches(); | 913 invalidateImageCaches(); |
913 | 914 |
914 m_imageCaches.erase(view->getId()); | 915 m_imageCaches.erase(view->getId()); |
915 | 916 |
916 if (m_fftModels.find(view->getId()) != m_fftModels.end()) { | 917 //!!! in theory we should call invalidateFFTModel() if and |
917 | 918 //!!! only if there are no remaining views in which we are not |
918 if (m_sliceableModel == m_fftModels[view->getId()]) { | 919 //!!! dormant |
919 bool replaced = false; | |
920 for (ViewFFTMap::iterator i = m_fftModels.begin(); | |
921 i != m_fftModels.end(); ++i) { | |
922 if (i->second != m_sliceableModel) { | |
923 emit sliceableModelReplaced(m_sliceableModel, i->second); | |
924 replaced = true; | |
925 break; | |
926 } | |
927 } | |
928 if (!replaced) emit sliceableModelReplaced(m_sliceableModel, 0); | |
929 } | |
930 | |
931 delete m_fftModels[view->getId()]; | |
932 m_fftModels.erase(view->getId()); | |
933 | |
934 delete m_peakCaches[view->getId()]; | |
935 m_peakCaches.erase(view->getId()); | |
936 } | |
937 | 920 |
938 } else { | 921 } else { |
939 | 922 |
940 Layer::setLayerDormant(v, false); | 923 Layer::setLayerDormant(v, false); |
941 } | 924 } |
1266 { | 1249 { |
1267 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1250 if (!m_model || !m_model->isOK() || !m_model->isReady()) { |
1268 return false; | 1251 return false; |
1269 } | 1252 } |
1270 | 1253 |
1271 FFTModel *fft = getFFTModel(v); | 1254 FFTModel *fft = getFFTModel(); |
1272 if (!fft) return false; | 1255 if (!fft) return false; |
1273 | 1256 |
1274 double s0 = 0, s1 = 0; | 1257 double s0 = 0, s1 = 0; |
1275 if (!getXBinRange(v, x, s0, s1)) return false; | 1258 if (!getXBinRange(v, x, s0, s1)) return false; |
1276 | 1259 |
1347 int s0i = int(s0 + 0.001); | 1330 int s0i = int(s0 + 0.001); |
1348 int s1i = int(s1); | 1331 int s1i = int(s1); |
1349 | 1332 |
1350 bool rv = false; | 1333 bool rv = false; |
1351 | 1334 |
1352 FFTModel *fft = getFFTModel(v); | 1335 FFTModel *fft = getFFTModel(); |
1353 | 1336 |
1354 if (fft) { | 1337 if (fft) { |
1355 | 1338 |
1356 int cw = fft->getWidth(); | 1339 int cw = fft->getWidth(); |
1357 int ch = fft->getHeight(); | 1340 int ch = fft->getHeight(); |
1388 | 1371 |
1389 return rv; | 1372 return rv; |
1390 } | 1373 } |
1391 | 1374 |
1392 FFTModel * | 1375 FFTModel * |
1393 SpectrogramLayer::getFFTModel(const LayerGeometryProvider *v) const | 1376 SpectrogramLayer::getFFTModel() const |
1394 { | 1377 { |
1395 if (!m_model) return 0; | 1378 if (!m_model) return 0; |
1396 | 1379 |
1397 int fftSize = getFFTSize(); | 1380 int fftSize = getFFTSize(); |
1398 | 1381 |
1399 const View *view = v->getView(); | 1382 //!!! it is now surely slower to do this on every getFFTModel() |
1400 | 1383 //!!! request than it would be to recreate the model immediately |
1401 if (m_fftModels.find(view->getId()) != m_fftModels.end()) { | 1384 //!!! when something changes instead of just invalidating it |
1402 if (m_fftModels[view->getId()] == 0) { | 1385 |
1403 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1386 if (m_fftModel && |
1404 cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found null model" << endl; | 1387 m_fftModel->getHeight() == fftSize / 2 + 1 && |
1405 #endif | 1388 m_fftModel->getWindowIncrement() == getWindowIncrement()) { |
1406 return 0; | 1389 return m_fftModel; |
1407 } | 1390 } |
1408 if (m_fftModels[view->getId()]->getHeight() != fftSize / 2 + 1) { | 1391 |
1409 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1392 delete m_peakCache; |
1410 cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a model with the wrong height (" << m_fftModels[view->getId()]->getHeight() << ", wanted " << (fftSize / 2 + 1) << ")" << endl; | 1393 m_peakCache = 0; |
1411 #endif | 1394 |
1412 delete m_fftModels[view->getId()]; | 1395 delete m_fftModel; |
1413 m_fftModels.erase(view->getId()); | 1396 m_fftModel = new FFTModel(m_model, |
1414 delete m_peakCaches[view->getId()]; | 1397 m_channel, |
1415 m_peakCaches.erase(view->getId()); | 1398 m_windowType, |
1416 } else { | 1399 m_windowSize, |
1417 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1400 getWindowIncrement(), |
1418 cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[view->getId()]->getHeight() << endl; | 1401 fftSize); |
1419 #endif | 1402 |
1420 return m_fftModels[view->getId()]; | 1403 if (!m_fftModel->isOK()) { |
1421 } | 1404 QMessageBox::critical |
1422 } | 1405 (0, tr("FFT cache failed"), |
1423 | 1406 tr("Failed to create the FFT model for this spectrogram.\n" |
1424 if (m_fftModels.find(view->getId()) == m_fftModels.end()) { | 1407 "There may be insufficient memory or disc space to continue.")); |
1425 | 1408 delete m_fftModel; |
1426 FFTModel *model = new FFTModel(m_model, | 1409 m_fftModel = 0; |
1427 m_channel, | 1410 return 0; |
1428 m_windowType, | 1411 } |
1429 m_windowSize, | 1412 |
1430 getWindowIncrement(), | 1413 ((SpectrogramLayer *)this)->sliceableModelReplaced(0, m_fftModel); |
1431 fftSize); | 1414 |
1432 | 1415 return m_fftModel; |
1433 if (!model->isOK()) { | |
1434 QMessageBox::critical | |
1435 (0, tr("FFT cache failed"), | |
1436 tr("Failed to create the FFT model for this spectrogram.\n" | |
1437 "There may be insufficient memory or disc space to continue.")); | |
1438 delete model; | |
1439 m_fftModels[view->getId()] = 0; | |
1440 return 0; | |
1441 } | |
1442 | |
1443 if (!m_sliceableModel) { | |
1444 #ifdef DEBUG_SPECTROGRAM | |
1445 cerr << "SpectrogramLayer: emitting sliceableModelReplaced(0, " << model << ")" << endl; | |
1446 #endif | |
1447 ((SpectrogramLayer *)this)->sliceableModelReplaced(0, model); | |
1448 m_sliceableModel = model; | |
1449 } | |
1450 | |
1451 m_fftModels[view->getId()] = model; | |
1452 } | |
1453 | |
1454 return m_fftModels[view->getId()]; | |
1455 } | 1416 } |
1456 | 1417 |
1457 Dense3DModelPeakCache * | 1418 Dense3DModelPeakCache * |
1458 SpectrogramLayer::getPeakCache(const LayerGeometryProvider *v) const | 1419 SpectrogramLayer::getPeakCache() const |
1459 { | 1420 { |
1460 const View *view = v->getView(); | 1421 //!!! see comment in getFFTModel |
1461 if (!m_peakCaches[view->getId()]) { | 1422 |
1462 FFTModel *f = getFFTModel(v); | 1423 if (!m_peakCache) { |
1424 FFTModel *f = getFFTModel(); | |
1463 if (!f) return 0; | 1425 if (!f) return 0; |
1464 m_peakCaches[view->getId()] = | 1426 m_peakCache = new Dense3DModelPeakCache(f, m_peakCacheDivisor); |
1465 new Dense3DModelPeakCache(f, m_peakCacheDivisor); | 1427 } |
1466 } | 1428 return m_peakCache; |
1467 return m_peakCaches[view->getId()]; | |
1468 } | 1429 } |
1469 | 1430 |
1470 const Model * | 1431 const Model * |
1471 SpectrogramLayer::getSliceableModel() const | 1432 SpectrogramLayer::getSliceableModel() const |
1472 { | 1433 { |
1473 if (m_sliceableModel) return m_sliceableModel; | 1434 return m_fftModel; |
1474 if (m_fftModels.empty()) return 0; | 1435 } |
1475 m_sliceableModel = m_fftModels.begin()->second; | 1436 |
1476 return m_sliceableModel; | 1437 void |
1477 } | 1438 SpectrogramLayer::invalidateFFTModel() |
1478 | |
1479 void | |
1480 SpectrogramLayer::invalidateFFTModels() | |
1481 { | 1439 { |
1482 #ifdef DEBUG_SPECTROGRAM | 1440 #ifdef DEBUG_SPECTROGRAM |
1483 cerr << "SpectrogramLayer::invalidateFFTModels called" << endl; | 1441 cerr << "SpectrogramLayer::invalidateFFTModel called" << endl; |
1484 #endif | 1442 #endif |
1485 for (ViewFFTMap::iterator i = m_fftModels.begin(); | 1443 |
1486 i != m_fftModels.end(); ++i) { | 1444 emit sliceableModelReplaced(m_fftModel, 0); |
1487 delete i->second; | 1445 |
1488 } | 1446 delete m_fftModel; |
1489 for (PeakCacheMap::iterator i = m_peakCaches.begin(); | 1447 delete m_peakCache; |
1490 i != m_peakCaches.end(); ++i) { | 1448 |
1491 delete i->second; | 1449 m_fftModel = 0; |
1492 } | 1450 m_peakCache = 0; |
1493 | |
1494 m_fftModels.clear(); | |
1495 m_peakCaches.clear(); | |
1496 | |
1497 if (m_sliceableModel) { | |
1498 cerr << "SpectrogramLayer: emitting sliceableModelReplaced(" << m_sliceableModel << ", 0)" << endl; | |
1499 emit sliceableModelReplaced(m_sliceableModel, 0); | |
1500 m_sliceableModel = 0; | |
1501 } | |
1502 } | 1451 } |
1503 | 1452 |
1504 void | 1453 void |
1505 SpectrogramLayer::invalidateMagnitudes() | 1454 SpectrogramLayer::invalidateMagnitudes() |
1506 { | 1455 { |
2142 cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; | 2091 cerr << "SpectrogramLayer::paintDrawBufferPeakFrequencies: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; |
2143 #endif | 2092 #endif |
2144 if (minbin < 0) minbin = 0; | 2093 if (minbin < 0) minbin = 0; |
2145 if (maxbin < 0) maxbin = minbin+1; | 2094 if (maxbin < 0) maxbin = minbin+1; |
2146 | 2095 |
2147 FFTModel *fft = getFFTModel(v); | 2096 FFTModel *fft = getFFTModel(); |
2148 if (!fft) return 0; | 2097 if (!fft) return 0; |
2149 | 2098 |
2150 FFTModel::PeakSet peakfreqs; | 2099 FFTModel::PeakSet peakfreqs; |
2151 vector<float> preparedColumn; | 2100 vector<float> preparedColumn; |
2152 | 2101 |
2367 cerr << "SpectrogramLayer::paintDrawBuffer: Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; | 2316 cerr << "SpectrogramLayer::paintDrawBuffer: Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; |
2368 #endif | 2317 #endif |
2369 | 2318 |
2370 int divisor = 1; | 2319 int divisor = 1; |
2371 if (usePeaksCache) { | 2320 if (usePeaksCache) { |
2372 peakCacheModel = getPeakCache(v); | 2321 peakCacheModel = getPeakCache(); |
2373 divisor = m_peakCacheDivisor; | 2322 divisor = m_peakCacheDivisor; |
2374 sourceModel = peakCacheModel; | 2323 sourceModel = peakCacheModel; |
2375 } else { | 2324 } else { |
2376 fftModel = getFFTModel(v); | 2325 fftModel = getFFTModel(); |
2377 sourceModel = fftModel; | 2326 sourceModel = fftModel; |
2378 } | 2327 } |
2379 | 2328 |
2380 if (!sourceModel) return 0; | 2329 if (!sourceModel) return 0; |
2381 | 2330 |
2596 } | 2545 } |
2597 | 2546 |
2598 int | 2547 int |
2599 SpectrogramLayer::getCompletion(LayerGeometryProvider *v) const | 2548 SpectrogramLayer::getCompletion(LayerGeometryProvider *v) const |
2600 { | 2549 { |
2601 const View *view = v->getView(); | 2550 if (!m_fftModel) return 100; |
2602 | 2551 int completion = m_fftModel->getCompletion(); |
2603 if (m_fftModels.find(view->getId()) == m_fftModels.end()) return 100; | |
2604 | |
2605 int completion = m_fftModels[view->getId()]->getCompletion(); | |
2606 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2552 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2607 cerr << "SpectrogramLayer::getCompletion: completion = " << completion << endl; | 2553 cerr << "SpectrogramLayer::getCompletion: completion = " << completion << endl; |
2608 #endif | 2554 #endif |
2609 return completion; | 2555 return completion; |
2610 } | 2556 } |
2611 | 2557 |
2612 QString | 2558 QString |
2613 SpectrogramLayer::getError(LayerGeometryProvider *v) const | 2559 SpectrogramLayer::getError(LayerGeometryProvider *v) const |
2614 { | 2560 { |
2615 const View *view = v->getView(); | 2561 const View *view = v->getView(); |
2616 if (m_fftModels.find(view->getId()) == m_fftModels.end()) return ""; | 2562 if (!m_fftModel) return ""; |
2617 return m_fftModels[view->getId()]->getError(); | 2563 return m_fftModel->getError(); |
2618 } | 2564 } |
2619 | 2565 |
2620 bool | 2566 bool |
2621 SpectrogramLayer::getValueExtents(double &min, double &max, | 2567 SpectrogramLayer::getValueExtents(double &min, double &max, |
2622 bool &logarithmic, QString &unit) const | 2568 bool &logarithmic, QString &unit) const |