Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 114:991de8783cf5
* Add fuzzy-adapter class to pick out subset data from FFT data server, instead
of having separate methods in data server class. Update spectrogram to use it.
* Give spectrogram layer one fft adapter per view, in case the views need
different zero-padding levels.
* Reduce ridiculous memory consumption of MatrixFile for tall matrices.
Still very much work in progress here.
author | Chris Cannam |
---|---|
date | Fri, 30 Jun 2006 11:26:10 +0000 |
parents | 7a23edd831cb |
children | 47cb32bb35ab |
comparison
equal
deleted
inserted
replaced
113:7a23edd831cb | 114:991de8783cf5 |
---|---|
53 m_colourScale(dBColourScale), | 53 m_colourScale(dBColourScale), |
54 m_colourScheme(DefaultColours), | 54 m_colourScheme(DefaultColours), |
55 m_frequencyScale(LinearFrequencyScale), | 55 m_frequencyScale(LinearFrequencyScale), |
56 m_binDisplay(AllBins), | 56 m_binDisplay(AllBins), |
57 m_normalizeColumns(false), | 57 m_normalizeColumns(false), |
58 m_fftServer(0), | |
59 m_updateTimer(0), | 58 m_updateTimer(0), |
60 m_candidateFillStartFrame(0), | 59 m_candidateFillStartFrame(0), |
61 m_lastFillExtent(0), | 60 m_lastFillExtent(0), |
62 m_exiting(false) | 61 m_exiting(false) |
63 { | 62 { |
85 SpectrogramLayer::~SpectrogramLayer() | 84 SpectrogramLayer::~SpectrogramLayer() |
86 { | 85 { |
87 delete m_updateTimer; | 86 delete m_updateTimer; |
88 m_updateTimer = 0; | 87 m_updateTimer = 0; |
89 | 88 |
90 if (m_fftServer) { | 89 invalidateFFTAdapters(); |
91 FFTDataServer::releaseInstance(m_fftServer); | |
92 m_fftServer = 0; | |
93 } | |
94 } | 90 } |
95 | 91 |
96 void | 92 void |
97 SpectrogramLayer::setModel(const DenseTimeValueModel *model) | 93 SpectrogramLayer::setModel(const DenseTimeValueModel *model) |
98 { | 94 { |
99 // std::cerr << "SpectrogramLayer(" << this << "): setModel(" << model << ")" << std::endl; | 95 // std::cerr << "SpectrogramLayer(" << this << "): setModel(" << model << ")" << std::endl; |
100 | 96 |
101 if (model == m_model) return; | 97 if (model == m_model) return; |
102 | 98 |
103 m_model = model; | 99 m_model = model; |
104 getFFTServer(); | 100 invalidateFFTAdapters(); |
105 | 101 |
106 if (!m_model || !m_model->isOK()) return; | 102 if (!m_model || !m_model->isOK()) return; |
107 | 103 |
108 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); | 104 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); |
109 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | 105 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), |
116 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | 112 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), |
117 this, SLOT(cacheInvalid(size_t, size_t))); | 113 this, SLOT(cacheInvalid(size_t, size_t))); |
118 | 114 |
119 emit modelReplaced(); | 115 emit modelReplaced(); |
120 } | 116 } |
121 | 117 /*!!! |
122 void | 118 void |
123 SpectrogramLayer::getFFTServer() | 119 SpectrogramLayer::invalidateFFTAdapters() |
124 { | 120 { |
125 if (m_fftServer) { | 121 // if (m_fftServer) { |
126 FFTDataServer::releaseInstance(m_fftServer); | 122 // FFTDataServer::releaseInstance(m_fftServer); |
127 m_fftServer = 0; | 123 // m_fftServer = 0; |
128 } | 124 // } |
125 | |
126 delete m_fftServer; | |
127 m_fftServer = 0; | |
129 | 128 |
130 if (m_model) { | 129 if (m_model) { |
131 m_fftServer = FFTDataServer::getFuzzyInstance(m_model, | 130 // m_fftServer = FFTDataServer::getFuzzyInstance(m_model, |
131 m_fftServer = new FFTFuzzyAdapter(m_model, | |
132 m_channel, | 132 m_channel, |
133 m_windowType, | 133 m_windowType, |
134 m_windowSize, | 134 m_windowSize, |
135 getWindowIncrement(), | 135 getWindowIncrement(), |
136 m_fftSize, | 136 m_fftSize, |
143 m_updateTimer = new QTimer(this); | 143 m_updateTimer = new QTimer(this); |
144 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut())); | 144 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut())); |
145 m_updateTimer->start(200); | 145 m_updateTimer->start(200); |
146 } | 146 } |
147 } | 147 } |
148 | 148 */ |
149 Layer::PropertyList | 149 Layer::PropertyList |
150 SpectrogramLayer::getProperties() const | 150 SpectrogramLayer::getProperties() const |
151 { | 151 { |
152 PropertyList list; | 152 PropertyList list; |
153 list.push_back("Colour"); | 153 list.push_back("Colour"); |
571 { | 571 { |
572 if (m_channel == ch) return; | 572 if (m_channel == ch) return; |
573 | 573 |
574 invalidatePixmapCaches(); | 574 invalidatePixmapCaches(); |
575 m_channel = ch; | 575 m_channel = ch; |
576 getFFTServer(); | 576 invalidateFFTAdapters(); |
577 | 577 |
578 emit layerParametersChanged(); | 578 emit layerParametersChanged(); |
579 } | 579 } |
580 | 580 |
581 int | 581 int |
592 invalidatePixmapCaches(); | 592 invalidatePixmapCaches(); |
593 | 593 |
594 m_windowSize = ws; | 594 m_windowSize = ws; |
595 m_fftSize = ws * (m_zeroPadLevel + 1); | 595 m_fftSize = ws * (m_zeroPadLevel + 1); |
596 | 596 |
597 getFFTServer(); | 597 invalidateFFTAdapters(); |
598 | 598 |
599 emit layerParametersChanged(); | 599 emit layerParametersChanged(); |
600 } | 600 } |
601 | 601 |
602 size_t | 602 size_t |
612 | 612 |
613 invalidatePixmapCaches(); | 613 invalidatePixmapCaches(); |
614 | 614 |
615 m_windowHopLevel = v; | 615 m_windowHopLevel = v; |
616 | 616 |
617 getFFTServer(); | 617 invalidateFFTAdapters(); |
618 | 618 |
619 emit layerParametersChanged(); | 619 emit layerParametersChanged(); |
620 | 620 |
621 // fillCache(); | 621 // fillCache(); |
622 } | 622 } |
635 invalidatePixmapCaches(); | 635 invalidatePixmapCaches(); |
636 | 636 |
637 m_zeroPadLevel = v; | 637 m_zeroPadLevel = v; |
638 m_fftSize = m_windowSize * (v + 1); | 638 m_fftSize = m_windowSize * (v + 1); |
639 | 639 |
640 getFFTServer(); | 640 invalidateFFTAdapters(); |
641 | 641 |
642 emit layerParametersChanged(); | 642 emit layerParametersChanged(); |
643 } | 643 } |
644 | 644 |
645 size_t | 645 size_t |
655 | 655 |
656 invalidatePixmapCaches(); | 656 invalidatePixmapCaches(); |
657 | 657 |
658 m_windowType = w; | 658 m_windowType = w; |
659 | 659 |
660 getFFTServer(); | 660 invalidateFFTAdapters(); |
661 | 661 |
662 emit layerParametersChanged(); | 662 emit layerParametersChanged(); |
663 } | 663 } |
664 | 664 |
665 WindowType | 665 WindowType |
857 | 857 |
858 m_dormancy[v] = true; | 858 m_dormancy[v] = true; |
859 | 859 |
860 invalidatePixmapCaches(); | 860 invalidatePixmapCaches(); |
861 m_pixmapCaches.erase(v); | 861 m_pixmapCaches.erase(v); |
862 | |
863 if (m_fftAdapters.find(v) != m_fftAdapters.end()) { | |
864 delete m_fftAdapters[v]; | |
865 m_fftAdapters.erase(v); | |
866 } | |
862 | 867 |
863 } else { | 868 } else { |
864 | 869 |
865 m_dormancy[v] = false; | 870 m_dormancy[v] = false; |
866 } | 871 } |
880 } | 885 } |
881 | 886 |
882 void | 887 void |
883 SpectrogramLayer::fillTimerTimedOut() | 888 SpectrogramLayer::fillTimerTimedOut() |
884 { | 889 { |
890 /*!!! | |
885 if (m_fftServer && m_model) { | 891 if (m_fftServer && m_model) { |
886 | 892 |
887 size_t fillExtent = m_fftServer->getFillExtent(); | 893 size_t fillExtent = m_fftServer->getFillExtent(); |
888 #ifdef DEBUG_SPECTROGRAM_REPAINT | 894 #ifdef DEBUG_SPECTROGRAM_REPAINT |
889 std::cerr << "SpectrogramLayer::fillTimerTimedOut: extent " << fillExtent << ", last " << m_lastFillExtent << ", total " << m_model->getEndFrame() << std::endl; | 895 std::cerr << "SpectrogramLayer::fillTimerTimedOut: extent " << fillExtent << ", last " << m_lastFillExtent << ", total " << m_model->getEndFrame() << std::endl; |
915 invalidatePixmapCaches(); | 921 invalidatePixmapCaches(); |
916 emit modelChanged(m_model->getStartFrame(), m_model->getEndFrame()); | 922 emit modelChanged(m_model->getStartFrame(), m_model->getEndFrame()); |
917 m_lastFillExtent = fillExtent; | 923 m_lastFillExtent = fillExtent; |
918 } | 924 } |
919 } | 925 } |
926 */ | |
920 } | 927 } |
921 | 928 |
922 void | 929 void |
923 SpectrogramLayer::setColourmap() | 930 SpectrogramLayer::setColourmap() |
924 { | 931 { |
996 } | 1003 } |
997 | 1004 |
998 void | 1005 void |
999 SpectrogramLayer::rotateColourmap(int distance) | 1006 SpectrogramLayer::rotateColourmap(int distance) |
1000 { | 1007 { |
1001 if (!m_fftServer) return; | |
1002 | |
1003 QColor newPixels[256]; | 1008 QColor newPixels[256]; |
1004 | 1009 |
1005 newPixels[NO_VALUE] = m_colourMap.getColour(NO_VALUE); | 1010 newPixels[NO_VALUE] = m_colourMap.getColour(NO_VALUE); |
1006 | 1011 |
1007 for (int pixel = 1; pixel < 256; ++pixel) { | 1012 for (int pixel = 1; pixel < 256; ++pixel) { |
1167 float minf = getEffectiveMinFrequency(); | 1172 float minf = getEffectiveMinFrequency(); |
1168 float maxf = getEffectiveMaxFrequency(); | 1173 float maxf = getEffectiveMaxFrequency(); |
1169 | 1174 |
1170 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 1175 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
1171 | 1176 |
1177 //!!! wrong for smoothing -- wrong fft size for fft adapter | |
1178 | |
1172 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); | 1179 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); |
1173 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); | 1180 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); |
1174 | 1181 |
1175 // Now map these on to actual bins | 1182 // Now map these on to actual bins |
1176 | 1183 |
1239 | 1246 |
1240 int q0i = int(q0 + 0.001); | 1247 int q0i = int(q0 + 0.001); |
1241 int q1i = int(q1); | 1248 int q1i = int(q1); |
1242 | 1249 |
1243 int sr = m_model->getSampleRate(); | 1250 int sr = m_model->getSampleRate(); |
1251 | |
1252 //!!! wrong for smoothing -- wrong fft size for fft adapter | |
1244 | 1253 |
1245 for (int q = q0i; q <= q1i; ++q) { | 1254 for (int q = q0i; q <= q1i; ++q) { |
1246 int binfreq = (sr * q) / m_fftSize; | 1255 int binfreq = (sr * q) / m_fftSize; |
1247 if (q == q0i) freqMin = binfreq; | 1256 if (q == q0i) freqMin = binfreq; |
1248 if (q == q1i) freqMax = binfreq; | 1257 if (q == q1i) freqMax = binfreq; |
1254 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, | 1263 SpectrogramLayer::getAdjustedYBinSourceRange(View *v, int x, int y, |
1255 float &freqMin, float &freqMax, | 1264 float &freqMin, float &freqMax, |
1256 float &adjFreqMin, float &adjFreqMax) | 1265 float &adjFreqMin, float &adjFreqMax) |
1257 const | 1266 const |
1258 { | 1267 { |
1259 if (!m_fftServer) return false; | 1268 FFTFuzzyAdapter *fft = getFFTAdapter(v); |
1269 if (!fft) return false; | |
1260 | 1270 |
1261 float s0 = 0, s1 = 0; | 1271 float s0 = 0, s1 = 0; |
1262 if (!getXBinRange(v, x, s0, s1)) return false; | 1272 if (!getXBinRange(v, x, s0, s1)) return false; |
1263 | 1273 |
1264 float q0 = 0, q1 = 0; | 1274 float q0 = 0, q1 = 0; |
1286 | 1296 |
1287 float binfreq = (sr * q) / m_windowSize; | 1297 float binfreq = (sr * q) / m_windowSize; |
1288 if (q == q0i) freqMin = binfreq; | 1298 if (q == q0i) freqMin = binfreq; |
1289 if (q == q1i) freqMax = binfreq; | 1299 if (q == q1i) freqMax = binfreq; |
1290 | 1300 |
1291 if (peaksOnly && !isFFTLocalPeak(s, q)) continue; | 1301 if (peaksOnly && !fft->isLocalPeak(s, q)) continue; |
1292 | 1302 |
1293 if (!isFFTOverThreshold(s, q, m_threshold)) continue; | 1303 if (!fft->isOverThreshold(s, q, m_threshold)) continue; |
1294 | 1304 |
1295 float freq = binfreq; | 1305 float freq = binfreq; |
1296 bool steady = false; | 1306 bool steady = false; |
1297 | 1307 |
1298 if (s < int(getFFTWidth()) - 1) { | 1308 if (s < int(fft->getWidth()) - 1) { |
1299 | 1309 |
1300 freq = calculateFrequency(q, | 1310 freq = calculateFrequency(q, |
1301 windowSize, | 1311 windowSize, |
1302 windowIncrement, | 1312 windowIncrement, |
1303 sr, | 1313 sr, |
1304 getFFTPhaseAt(s, q), | 1314 fft->getPhaseAt(s, q), |
1305 getFFTPhaseAt(s+1, q), | 1315 fft->getPhaseAt(s+1, q), |
1306 steady); | 1316 steady); |
1307 | 1317 |
1308 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq; | 1318 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq; |
1309 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq; | 1319 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq; |
1310 | 1320 |
1337 int s0i = int(s0 + 0.001); | 1347 int s0i = int(s0 + 0.001); |
1338 int s1i = int(s1); | 1348 int s1i = int(s1); |
1339 | 1349 |
1340 bool rv = false; | 1350 bool rv = false; |
1341 | 1351 |
1342 if (m_fftServer) { | 1352 FFTFuzzyAdapter *fft = getFFTAdapter(v); |
1343 | 1353 |
1344 int cw = getFFTWidth(); | 1354 if (fft) { |
1345 int ch = getFFTHeight(); | 1355 |
1356 int cw = fft->getWidth(); | |
1357 int ch = fft->getHeight(); | |
1346 | 1358 |
1347 min = 0.0; | 1359 min = 0.0; |
1348 max = 0.0; | 1360 max = 0.0; |
1349 phaseMin = 0.0; | 1361 phaseMin = 0.0; |
1350 phaseMax = 0.0; | 1362 phaseMax = 0.0; |
1354 for (int s = s0i; s <= s1i; ++s) { | 1366 for (int s = s0i; s <= s1i; ++s) { |
1355 if (s >= 0 && q >= 0 && s < cw && q < ch) { | 1367 if (s >= 0 && q >= 0 && s < cw && q < ch) { |
1356 | 1368 |
1357 float value; | 1369 float value; |
1358 | 1370 |
1359 value = getFFTPhaseAt(s, q); | 1371 value = fft->getPhaseAt(s, q); |
1360 if (!have || value < phaseMin) { phaseMin = value; } | 1372 if (!have || value < phaseMin) { phaseMin = value; } |
1361 if (!have || value > phaseMax) { phaseMax = value; } | 1373 if (!have || value > phaseMax) { phaseMax = value; } |
1362 | 1374 |
1363 value = getFFTMagnitudeAt(s, q); | 1375 value = fft->getMagnitudeAt(s, q); |
1364 if (!have || value < min) { min = value; } | 1376 if (!have || value < min) { min = value; } |
1365 if (!have || value > max) { max = value; } | 1377 if (!have || value > max) { max = value; } |
1366 | 1378 |
1367 have = true; | 1379 have = true; |
1368 } | 1380 } |
1375 } | 1387 } |
1376 | 1388 |
1377 return rv; | 1389 return rv; |
1378 } | 1390 } |
1379 | 1391 |
1392 size_t | |
1393 SpectrogramLayer::getZeroPadLevel(const View *v) const | |
1394 { | |
1395 //!!! tidy all this stuff | |
1396 | |
1397 if (m_binDisplay != AllBins) return 0; | |
1398 if (m_frequencyScale == LogFrequencyScale) return 3; | |
1399 | |
1400 int sr = m_model->getSampleRate(); | |
1401 | |
1402 size_t bins = m_fftSize / 2; | |
1403 if (m_maxFrequency > 0) { | |
1404 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); | |
1405 if (bins > m_fftSize / 2) bins = m_fftSize / 2; | |
1406 } | |
1407 | |
1408 size_t minbin = 1; | |
1409 if (m_minFrequency > 0) { | |
1410 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); | |
1411 if (minbin < 1) minbin = 1; | |
1412 if (minbin >= bins) minbin = bins - 1; | |
1413 } | |
1414 | |
1415 if (v->height() / 1.5 > (bins - minbin) / (m_zeroPadLevel + 1)) { | |
1416 return 3; | |
1417 } else { | |
1418 return 0; | |
1419 } | |
1420 } | |
1421 | |
1422 size_t | |
1423 SpectrogramLayer::getFFTSize(const View *v) const | |
1424 { | |
1425 return m_fftSize * (getZeroPadLevel(v) + 1); | |
1426 } | |
1427 | |
1428 FFTFuzzyAdapter * | |
1429 SpectrogramLayer::getFFTAdapter(const View *v) const | |
1430 { | |
1431 if (!m_model) return 0; | |
1432 | |
1433 size_t fftSize = getFFTSize(v); | |
1434 | |
1435 if (m_fftAdapters.find(v) != m_fftAdapters.end()) { | |
1436 if (m_fftAdapters[v]->getHeight() != fftSize / 2) { | |
1437 delete m_fftAdapters[v]; | |
1438 m_fftAdapters.erase(v); | |
1439 } | |
1440 } | |
1441 | |
1442 if (m_fftAdapters.find(v) == m_fftAdapters.end()) { | |
1443 m_fftAdapters[v] = new FFTFuzzyAdapter(m_model, | |
1444 m_channel, | |
1445 m_windowType, | |
1446 m_windowSize, | |
1447 getWindowIncrement(), | |
1448 getFFTSize(v), | |
1449 true, | |
1450 m_candidateFillStartFrame); | |
1451 m_lastFillExtent = 0; | |
1452 | |
1453 delete m_updateTimer; | |
1454 m_updateTimer = new QTimer((SpectrogramLayer *)this); | |
1455 connect(m_updateTimer, SIGNAL(timeout()), | |
1456 this, SLOT(fillTimerTimedOut())); | |
1457 m_updateTimer->start(200); | |
1458 } | |
1459 | |
1460 return m_fftAdapters[v]; | |
1461 } | |
1462 | |
1463 void | |
1464 SpectrogramLayer::invalidateFFTAdapters() | |
1465 { | |
1466 for (ViewFFTMap::iterator i = m_fftAdapters.begin(); | |
1467 i != m_fftAdapters.end(); ++i) { | |
1468 delete i->second; | |
1469 } | |
1470 | |
1471 m_fftAdapters.clear(); | |
1472 } | |
1473 | |
1380 void | 1474 void |
1381 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const | 1475 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const |
1382 { | 1476 { |
1383 if (m_colourScheme == BlackOnWhite) { | 1477 if (m_colourScheme == BlackOnWhite) { |
1384 v->setLightBackground(true); | 1478 v->setLightBackground(true); |
1409 // is not in the dormancy map at all -- we need it to be present | 1503 // is not in the dormancy map at all -- we need it to be present |
1410 // and accountable for when determining whether we need the cache | 1504 // and accountable for when determining whether we need the cache |
1411 // in the cache-fill thread above. | 1505 // in the cache-fill thread above. |
1412 m_dormancy[v] = false; | 1506 m_dormancy[v] = false; |
1413 | 1507 |
1414 if (!m_fftServer) { // lock the mutex before checking this | 1508 size_t fftSize = getFFTSize(v); |
1415 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1509 FFTFuzzyAdapter *fft = getFFTAdapter(v); |
1416 std::cerr << "SpectrogramLayer::paint(): No FFT server, returning" << std::endl; | 1510 if (!fft) { |
1417 #endif | 1511 std::cerr << "ERROR: SpectrogramLayer::paint(): No FFT adapter, returning" << std::endl; |
1418 return; | 1512 return; |
1419 } | 1513 } |
1420 | 1514 |
1421 PixmapCache &cache = m_pixmapCaches[v]; | 1515 PixmapCache &cache = m_pixmapCaches[v]; |
1422 | 1516 |
1621 | 1715 |
1622 m_drawBuffer.fill(m_colourMap.getColour(0).rgb()); | 1716 m_drawBuffer.fill(m_colourMap.getColour(0).rgb()); |
1623 | 1717 |
1624 int sr = m_model->getSampleRate(); | 1718 int sr = m_model->getSampleRate(); |
1625 | 1719 |
1626 size_t bins = m_fftSize / 2; | 1720 size_t bins = fftSize / 2; |
1627 if (m_maxFrequency > 0) { | 1721 if (m_maxFrequency > 0) { |
1628 bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); | 1722 bins = int((double(m_maxFrequency) * fftSize) / sr + 0.1); |
1629 if (bins > m_fftSize / 2) bins = m_fftSize / 2; | 1723 if (bins > fftSize / 2) bins = fftSize / 2; |
1630 } | 1724 } |
1631 | 1725 |
1632 size_t minbin = 1; | 1726 size_t minbin = 1; |
1633 if (m_minFrequency > 0) { | 1727 if (m_minFrequency > 0) { |
1634 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); | 1728 minbin = int((double(m_minFrequency) * fftSize) / sr + 0.1); |
1635 if (minbin < 1) minbin = 1; | 1729 if (minbin < 1) minbin = 1; |
1636 if (minbin >= bins) minbin = bins - 1; | 1730 if (minbin >= bins) minbin = bins - 1; |
1637 } | 1731 } |
1638 | 1732 |
1639 //!!! quite wrong and won't work for layers that may be in more than one view | 1733 float minFreq = (float(minbin) * sr) / fftSize; |
1640 if (v->height() / 1.5 > (bins - minbin) / (m_zeroPadLevel + 1)) { | 1734 float maxFreq = (float(bins) * sr) / fftSize; |
1641 if (m_zeroPadLevel != 3) { | |
1642 std::cerr << v->height()/1.5 << " > " << ((bins - minbin) / (m_zeroPadLevel + 1)) << ": switching to smoothed display" << std::endl; | |
1643 ((SpectrogramLayer *)this)->setZeroPadLevel(3); | |
1644 return; | |
1645 } | |
1646 } else { | |
1647 if (m_zeroPadLevel != 0) { | |
1648 ((SpectrogramLayer *)this)->setZeroPadLevel(0); | |
1649 return; | |
1650 } | |
1651 } | |
1652 | |
1653 float minFreq = (float(minbin) * sr) / m_fftSize; | |
1654 float maxFreq = (float(bins) * sr) / m_fftSize; | |
1655 | 1735 |
1656 float ymag[h]; | 1736 float ymag[h]; |
1657 float ydiv[h]; | 1737 float ydiv[h]; |
1658 float yval[bins + 1]; | 1738 float yval[bins + 1]; |
1659 | 1739 |
1660 size_t increment = getWindowIncrement(); | 1740 size_t increment = getWindowIncrement(); |
1661 | 1741 |
1662 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 1742 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
1663 | 1743 |
1664 for (size_t q = minbin; q <= bins; ++q) { | 1744 for (size_t q = minbin; q <= bins; ++q) { |
1665 float f0 = (float(q) * sr) / m_fftSize; | 1745 float f0 = (float(q) * sr) / fftSize; |
1666 yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic); | 1746 yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic); |
1667 } | 1747 } |
1668 | 1748 |
1669 for (int x = 0; x < w; ++x) { | 1749 for (int x = 0; x < w; ++x) { |
1670 | 1750 |
1681 } | 1761 } |
1682 | 1762 |
1683 int s0i = int(s0 + 0.001); | 1763 int s0i = int(s0 + 0.001); |
1684 int s1i = int(s1); | 1764 int s1i = int(s1); |
1685 | 1765 |
1686 if (s1i >= getFFTWidth()) { | 1766 if (s1i >= fft->getWidth()) { |
1687 if (s0i >= getFFTWidth()) { | 1767 if (s0i >= fft->getWidth()) { |
1688 continue; | 1768 continue; |
1689 } else { | 1769 } else { |
1690 s1i = s0i; | 1770 s1i = s0i; |
1691 } | 1771 } |
1692 } | 1772 } |
1693 | 1773 |
1694 for (int s = s0i; s <= s1i; ++s) { | 1774 for (int s = s0i; s <= s1i; ++s) { |
1695 | 1775 |
1696 if (!isFFTColumnReady(s)) continue; | 1776 if (!fft->isColumnReady(s)) continue; |
1697 | 1777 |
1698 for (size_t q = minbin; q < bins; ++q) { | 1778 for (size_t q = minbin; q < bins; ++q) { |
1699 | 1779 |
1700 float y0 = yval[q + 1]; | 1780 float y0 = yval[q + 1]; |
1701 float y1 = yval[q]; | 1781 float y1 = yval[q]; |
1702 | 1782 |
1703 if (m_binDisplay == PeakBins || | 1783 if (m_binDisplay == PeakBins || |
1704 m_binDisplay == PeakFrequencies) { | 1784 m_binDisplay == PeakFrequencies) { |
1705 if (!isFFTLocalPeak(s, q)) continue; | 1785 if (!fft->isLocalPeak(s, q)) continue; |
1706 } | 1786 } |
1707 | 1787 |
1708 if (!isFFTOverThreshold(s, q, m_threshold)) continue; | 1788 if (m_threshold != 0.f && |
1789 !fft->isOverThreshold(s, q, m_threshold)) { | |
1790 continue; | |
1791 } | |
1709 | 1792 |
1710 float sprop = 1.0; | 1793 float sprop = 1.0; |
1711 if (s == s0i) sprop *= (s + 1) - s0; | 1794 if (s == s0i) sprop *= (s + 1) - s0; |
1712 if (s == s1i) sprop *= s1 - s; | 1795 if (s == s1i) sprop *= s1 - s; |
1713 | 1796 |
1714 if (m_binDisplay == PeakFrequencies && | 1797 if (m_binDisplay == PeakFrequencies && |
1715 s < int(getFFTWidth()) - 1) { | 1798 s < int(fft->getWidth()) - 1) { |
1716 | 1799 |
1717 bool steady = false; | 1800 bool steady = false; |
1718 float f = calculateFrequency(q, | 1801 float f = calculateFrequency(q, |
1719 m_windowSize, | 1802 m_windowSize, |
1720 increment, | 1803 increment, |
1721 sr, | 1804 sr, |
1722 getFFTPhaseAt(s, q), | 1805 fft->getPhaseAt(s, q), |
1723 getFFTPhaseAt(s+1, q), | 1806 fft->getPhaseAt(s+1, q), |
1724 steady); | 1807 steady); |
1725 | 1808 |
1726 y0 = y1 = v->getYForFrequency | 1809 y0 = y1 = v->getYForFrequency |
1727 (f, minFreq, maxFreq, logarithmic); | 1810 (f, minFreq, maxFreq, logarithmic); |
1728 } | 1811 } |
1731 int y1i = int(y1); | 1814 int y1i = int(y1); |
1732 | 1815 |
1733 float value; | 1816 float value; |
1734 | 1817 |
1735 if (m_colourScale == PhaseColourScale) { | 1818 if (m_colourScale == PhaseColourScale) { |
1736 value = getFFTPhaseAt(s, q); | 1819 value = fft->getPhaseAt(s, q); |
1737 } else if (m_normalizeColumns) { | 1820 } else if (m_normalizeColumns) { |
1738 value = getFFTNormalizedMagnitudeAt(s, q) * m_gain; | 1821 value = fft->getNormalizedMagnitudeAt(s, q) * m_gain; |
1739 } else { | 1822 } else { |
1740 value = getFFTMagnitudeAt(s, q) * m_gain; | 1823 value = fft->getMagnitudeAt(s, q) * m_gain; |
1741 } | 1824 } |
1742 | 1825 |
1743 for (int y = y0i; y <= y1i; ++y) { | 1826 for (int y = y0i; y <= y1i; ++y) { |
1744 | 1827 |
1745 if (y < 0 || y >= h) continue; | 1828 if (y < 0 || y >= h) continue; |
1831 } | 1914 } |
1832 | 1915 |
1833 int | 1916 int |
1834 SpectrogramLayer::getCompletion() const | 1917 SpectrogramLayer::getCompletion() const |
1835 { | 1918 { |
1919 /*!!! | |
1836 if (m_updateTimer == 0 || !m_fftServer) return 100; | 1920 if (m_updateTimer == 0 || !m_fftServer) return 100; |
1837 size_t completion = m_fftServer->getFillCompletion(); | 1921 size_t completion = m_fftServer->getFillCompletion(); |
1838 // std::cerr << "SpectrogramLayer::getCompletion: completion = " << completion << std::endl; | 1922 // std::cerr << "SpectrogramLayer::getCompletion: completion = " << completion << std::endl; |
1839 return completion; | 1923 return completion; |
1924 */ | |
1925 return 100; | |
1840 } | 1926 } |
1841 | 1927 |
1842 bool | 1928 bool |
1843 SpectrogramLayer::getValueExtents(float &min, float &max, | 1929 SpectrogramLayer::getValueExtents(float &min, float &max, |
1844 bool &logarithmic, QString &unit) const | 1930 bool &logarithmic, QString &unit) const |
2115 | 2201 |
2116 int py = -1; | 2202 int py = -1; |
2117 int textHeight = paint.fontMetrics().height(); | 2203 int textHeight = paint.fontMetrics().height(); |
2118 int toff = -textHeight + paint.fontMetrics().ascent() + 2; | 2204 int toff = -textHeight + paint.fontMetrics().ascent() + 2; |
2119 | 2205 |
2120 if (m_fftServer && h > textHeight * 2 + 10) { | 2206 if (h > textHeight * 2 + 10) { |
2121 | 2207 |
2122 int ch = h - textHeight * 2 - 8; | 2208 int ch = h - textHeight * 2 - 8; |
2123 paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); | 2209 paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); |
2124 | 2210 |
2125 QString top, bottom; | 2211 QString top, bottom; |