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