Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 1473:886c1cd48f9d by-id
Further layer updates for ModelById
author | Chris Cannam |
---|---|
date | Tue, 02 Jul 2019 11:49:52 +0100 |
parents | dbff4b290bf0 |
children | e540aa5d89cd |
comparison
equal
deleted
inserted
replaced
1472:dbff4b290bf0 | 1473:886c1cd48f9d |
---|---|
80 m_normalizeVisibleArea(false), | 80 m_normalizeVisibleArea(false), |
81 m_lastEmittedZoomStep(-1), | 81 m_lastEmittedZoomStep(-1), |
82 m_synchronous(false), | 82 m_synchronous(false), |
83 m_haveDetailedScale(false), | 83 m_haveDetailedScale(false), |
84 m_exiting(false), | 84 m_exiting(false), |
85 m_wholeCache(nullptr), | |
86 m_peakCache(nullptr), | |
87 m_peakCacheDivisor(8) | 85 m_peakCacheDivisor(8) |
88 { | 86 { |
89 QString colourConfigName = "spectrogram-colour"; | 87 QString colourConfigName = "spectrogram-colour"; |
90 int colourConfigDefault = int(ColourMapper::Green); | 88 int colourConfigDefault = int(ColourMapper::Green); |
91 | 89 |
136 } | 134 } |
137 | 135 |
138 void | 136 void |
139 SpectrogramLayer::deleteDerivedModels() | 137 SpectrogramLayer::deleteDerivedModels() |
140 { | 138 { |
141 if (m_fftModel) m_fftModel->aboutToDelete(); | 139 ModelById::release(m_fftModel); |
142 if (m_peakCache) m_peakCache->aboutToDelete(); | 140 ModelById::release(m_peakCache); |
143 if (m_wholeCache) m_wholeCache->aboutToDelete(); | 141 ModelById::release(m_wholeCache); |
144 | 142 |
145 delete m_fftModel; | 143 m_fftModel = {}; |
146 delete m_peakCache; | 144 m_peakCache = {}; |
147 delete m_wholeCache; | 145 m_wholeCache = {}; |
148 | |
149 m_fftModel = nullptr; | |
150 m_peakCache = nullptr; | |
151 m_wholeCache = nullptr; | |
152 } | 146 } |
153 | 147 |
154 pair<ColourScaleType, double> | 148 pair<ColourScaleType, double> |
155 SpectrogramLayer::convertToColourScale(int value) | 149 SpectrogramLayer::convertToColourScale(int value) |
156 { | 150 { |
1105 } | 1099 } |
1106 | 1100 |
1107 double | 1101 double |
1108 SpectrogramLayer::getEffectiveMinFrequency() const | 1102 SpectrogramLayer::getEffectiveMinFrequency() const |
1109 { | 1103 { |
1110 sv_samplerate_t sr = m_model->getSampleRate(); | 1104 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1105 if (!model) return 0.0; | |
1106 | |
1107 sv_samplerate_t sr = model->getSampleRate(); | |
1111 double minf = double(sr) / getFFTSize(); | 1108 double minf = double(sr) / getFFTSize(); |
1112 | 1109 |
1113 if (m_minFrequency > 0.0) { | 1110 if (m_minFrequency > 0.0) { |
1114 int minbin = int((double(m_minFrequency) * getFFTSize()) / sr + 0.01); | 1111 int minbin = int((double(m_minFrequency) * getFFTSize()) / sr + 0.01); |
1115 if (minbin < 1) minbin = 1; | 1112 if (minbin < 1) minbin = 1; |
1120 } | 1117 } |
1121 | 1118 |
1122 double | 1119 double |
1123 SpectrogramLayer::getEffectiveMaxFrequency() const | 1120 SpectrogramLayer::getEffectiveMaxFrequency() const |
1124 { | 1121 { |
1125 sv_samplerate_t sr = m_model->getSampleRate(); | 1122 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1123 if (!model) return 0.0; | |
1124 | |
1125 sv_samplerate_t sr = model->getSampleRate(); | |
1126 double maxf = double(sr) / 2; | 1126 double maxf = double(sr) / 2; |
1127 | 1127 |
1128 if (m_maxFrequency > 0.0) { | 1128 if (m_maxFrequency > 0.0) { |
1129 int maxbin = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1); | 1129 int maxbin = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1); |
1130 if (maxbin > getFFTSize() / 2) maxbin = getFFTSize() / 2; | 1130 if (maxbin > getFFTSize() / 2) maxbin = getFFTSize() / 2; |
1146 } | 1146 } |
1147 | 1147 |
1148 double | 1148 double |
1149 SpectrogramLayer::getYForBin(const LayerGeometryProvider *v, double bin) const | 1149 SpectrogramLayer::getYForBin(const LayerGeometryProvider *v, double bin) const |
1150 { | 1150 { |
1151 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); | |
1152 if (!model) return 0.0; | |
1153 | |
1151 double minf = getEffectiveMinFrequency(); | 1154 double minf = getEffectiveMinFrequency(); |
1152 double maxf = getEffectiveMaxFrequency(); | 1155 double maxf = getEffectiveMaxFrequency(); |
1153 bool logarithmic = (m_binScale == BinScale::Log); | 1156 bool logarithmic = (m_binScale == BinScale::Log); |
1154 sv_samplerate_t sr = m_model->getSampleRate(); | 1157 sv_samplerate_t sr = model->getSampleRate(); |
1155 | 1158 |
1156 double freq = (bin * sr) / getFFTSize(); | 1159 double freq = (bin * sr) / getFFTSize(); |
1157 | 1160 |
1158 double y = v->getYForFrequency(freq, minf, maxf, logarithmic); | 1161 double y = v->getYForFrequency(freq, minf, maxf, logarithmic); |
1159 | 1162 |
1161 } | 1164 } |
1162 | 1165 |
1163 double | 1166 double |
1164 SpectrogramLayer::getBinForY(const LayerGeometryProvider *v, double y) const | 1167 SpectrogramLayer::getBinForY(const LayerGeometryProvider *v, double y) const |
1165 { | 1168 { |
1166 sv_samplerate_t sr = m_model->getSampleRate(); | 1169 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1170 if (!model) return 0.0; | |
1171 | |
1172 sv_samplerate_t sr = model->getSampleRate(); | |
1167 double minf = getEffectiveMinFrequency(); | 1173 double minf = getEffectiveMinFrequency(); |
1168 double maxf = getEffectiveMaxFrequency(); | 1174 double maxf = getEffectiveMaxFrequency(); |
1169 | 1175 |
1170 bool logarithmic = (m_binScale == BinScale::Log); | 1176 bool logarithmic = (m_binScale == BinScale::Log); |
1171 | 1177 |
1178 } | 1184 } |
1179 | 1185 |
1180 bool | 1186 bool |
1181 SpectrogramLayer::getXBinRange(LayerGeometryProvider *v, int x, double &s0, double &s1) const | 1187 SpectrogramLayer::getXBinRange(LayerGeometryProvider *v, int x, double &s0, double &s1) const |
1182 { | 1188 { |
1183 sv_frame_t modelStart = m_model->getStartFrame(); | 1189 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1184 sv_frame_t modelEnd = m_model->getEndFrame(); | 1190 if (!model) return false; |
1191 | |
1192 sv_frame_t modelStart = model->getStartFrame(); | |
1193 sv_frame_t modelEnd = model->getEndFrame(); | |
1185 | 1194 |
1186 // Each pixel column covers an exact range of sample frames: | 1195 // Each pixel column covers an exact range of sample frames: |
1187 sv_frame_t f0 = v->getFrameForX(x) - modelStart; | 1196 sv_frame_t f0 = v->getFrameForX(x) - modelStart; |
1188 sv_frame_t f1 = v->getFrameForX(x + 1) - modelStart - 1; | 1197 sv_frame_t f1 = v->getFrameForX(x + 1) - modelStart - 1; |
1189 | 1198 |
1202 } | 1211 } |
1203 | 1212 |
1204 bool | 1213 bool |
1205 SpectrogramLayer::getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &min, RealTime &max) const | 1214 SpectrogramLayer::getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &min, RealTime &max) const |
1206 { | 1215 { |
1216 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); | |
1217 if (!model) return false; | |
1218 | |
1207 double s0 = 0, s1 = 0; | 1219 double s0 = 0, s1 = 0; |
1208 if (!getXBinRange(v, x, s0, s1)) return false; | 1220 if (!getXBinRange(v, x, s0, s1)) return false; |
1209 | 1221 |
1210 int s0i = int(s0 + 0.001); | 1222 int s0i = int(s0 + 0.001); |
1211 int s1i = int(s1); | 1223 int s1i = int(s1); |
1213 int windowIncrement = getWindowIncrement(); | 1225 int windowIncrement = getWindowIncrement(); |
1214 int w0 = s0i * windowIncrement - (m_windowSize - windowIncrement)/2; | 1226 int w0 = s0i * windowIncrement - (m_windowSize - windowIncrement)/2; |
1215 int w1 = s1i * windowIncrement + windowIncrement + | 1227 int w1 = s1i * windowIncrement + windowIncrement + |
1216 (m_windowSize - windowIncrement)/2 - 1; | 1228 (m_windowSize - windowIncrement)/2 - 1; |
1217 | 1229 |
1218 min = RealTime::frame2RealTime(w0, m_model->getSampleRate()); | 1230 min = RealTime::frame2RealTime(w0, model->getSampleRate()); |
1219 max = RealTime::frame2RealTime(w1, m_model->getSampleRate()); | 1231 max = RealTime::frame2RealTime(w1, model->getSampleRate()); |
1220 return true; | 1232 return true; |
1221 } | 1233 } |
1222 | 1234 |
1223 bool | 1235 bool |
1224 SpectrogramLayer::getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) | 1236 SpectrogramLayer::getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) |
1225 const | 1237 const |
1226 { | 1238 { |
1239 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); | |
1240 if (!model) return false; | |
1241 | |
1227 double q0 = 0, q1 = 0; | 1242 double q0 = 0, q1 = 0; |
1228 if (!getYBinRange(v, y, q0, q1)) return false; | 1243 if (!getYBinRange(v, y, q0, q1)) return false; |
1229 | 1244 |
1230 int q0i = int(q0 + 0.001); | 1245 int q0i = int(q0 + 0.001); |
1231 int q1i = int(q1); | 1246 int q1i = int(q1); |
1232 | 1247 |
1233 sv_samplerate_t sr = m_model->getSampleRate(); | 1248 sv_samplerate_t sr = model->getSampleRate(); |
1234 | 1249 |
1235 for (int q = q0i; q <= q1i; ++q) { | 1250 for (int q = q0i; q <= q1i; ++q) { |
1236 if (q == q0i) freqMin = (sr * q) / getFFTSize(); | 1251 if (q == q0i) freqMin = (sr * q) / getFFTSize(); |
1237 if (q == q1i) freqMax = (sr * (q+1)) / getFFTSize(); | 1252 if (q == q1i) freqMax = (sr * (q+1)) / getFFTSize(); |
1238 } | 1253 } |
1243 SpectrogramLayer::getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, | 1258 SpectrogramLayer::getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, |
1244 double &freqMin, double &freqMax, | 1259 double &freqMin, double &freqMax, |
1245 double &adjFreqMin, double &adjFreqMax) | 1260 double &adjFreqMin, double &adjFreqMax) |
1246 const | 1261 const |
1247 { | 1262 { |
1248 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1263 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1264 if (!model || !model->isOK() || !model->isReady()) { | |
1249 return false; | 1265 return false; |
1250 } | 1266 } |
1251 | 1267 |
1252 FFTModel *fft = getFFTModel(); | 1268 auto fft = ModelById::getAs<FFTModel>(m_fftModel); |
1253 if (!fft) return false; | 1269 if (!fft) return false; |
1254 | 1270 |
1255 double s0 = 0, s1 = 0; | 1271 double s0 = 0, s1 = 0; |
1256 if (!getXBinRange(v, x, s0, s1)) return false; | 1272 if (!getXBinRange(v, x, s0, s1)) return false; |
1257 | 1273 |
1262 int s1i = int(s1); | 1278 int s1i = int(s1); |
1263 | 1279 |
1264 int q0i = int(q0 + 0.001); | 1280 int q0i = int(q0 + 0.001); |
1265 int q1i = int(q1); | 1281 int q1i = int(q1); |
1266 | 1282 |
1267 sv_samplerate_t sr = m_model->getSampleRate(); | 1283 sv_samplerate_t sr = model->getSampleRate(); |
1268 | 1284 |
1269 bool haveAdj = false; | 1285 bool haveAdj = false; |
1270 | 1286 |
1271 bool peaksOnly = (m_binDisplay == BinDisplay::PeakBins || | 1287 bool peaksOnly = (m_binDisplay == BinDisplay::PeakBins || |
1272 m_binDisplay == BinDisplay::PeakFrequencies); | 1288 m_binDisplay == BinDisplay::PeakFrequencies); |
1310 bool | 1326 bool |
1311 SpectrogramLayer::getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, | 1327 SpectrogramLayer::getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, |
1312 double &min, double &max, | 1328 double &min, double &max, |
1313 double &phaseMin, double &phaseMax) const | 1329 double &phaseMin, double &phaseMax) const |
1314 { | 1330 { |
1315 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1331 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1332 if (!model || !model->isOK() || !model->isReady()) { | |
1316 return false; | 1333 return false; |
1317 } | 1334 } |
1318 | 1335 |
1319 double q0 = 0, q1 = 0; | 1336 double q0 = 0, q1 = 0; |
1320 if (!getYBinRange(v, y, q0, q1)) return false; | 1337 if (!getYBinRange(v, y, q0, q1)) return false; |
1328 int s0i = int(s0 + 0.001); | 1345 int s0i = int(s0 + 0.001); |
1329 int s1i = int(s1); | 1346 int s1i = int(s1); |
1330 | 1347 |
1331 bool rv = false; | 1348 bool rv = false; |
1332 | 1349 |
1333 FFTModel *fft = getFFTModel(); | 1350 auto fft = ModelById::getAs<FFTModel>(m_fftModel); |
1334 | 1351 |
1335 if (fft) { | 1352 if (fft) { |
1336 | 1353 |
1337 int cw = fft->getWidth(); | 1354 int cw = fft->getWidth(); |
1338 int ch = fft->getHeight(); | 1355 int ch = fft->getHeight(); |
1373 void | 1390 void |
1374 SpectrogramLayer::recreateFFTModel() | 1391 SpectrogramLayer::recreateFFTModel() |
1375 { | 1392 { |
1376 SVDEBUG << "SpectrogramLayer::recreateFFTModel called" << endl; | 1393 SVDEBUG << "SpectrogramLayer::recreateFFTModel called" << endl; |
1377 | 1394 |
1378 if (!m_model || !m_model->isOK()) { | 1395 { // scope, avoid hanging on to this pointer |
1379 emit sliceableModelReplaced(m_fftModel, nullptr); | 1396 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1380 deleteDerivedModels(); | 1397 if (!model || !model->isOK()) { |
1381 return; | 1398 deleteDerivedModels(); |
1382 } | 1399 return; |
1383 | 1400 } |
1384 if (m_fftModel) m_fftModel->aboutToDelete(); | 1401 } |
1385 | 1402 |
1386 if (m_peakCache) m_peakCache->aboutToDelete(); | 1403 deleteDerivedModels(); |
1387 delete m_peakCache; | 1404 |
1388 m_peakCache = nullptr; | 1405 auto newFFTModel = std::make_shared<FFTModel>(m_model, |
1389 | 1406 m_channel, |
1390 if (m_wholeCache) m_wholeCache->aboutToDelete(); | 1407 m_windowType, |
1391 delete m_wholeCache; | 1408 m_windowSize, |
1392 m_wholeCache = nullptr; | 1409 getWindowIncrement(), |
1393 | 1410 getFFTSize()); |
1394 FFTModel *newModel = new FFTModel(m_model, | 1411 |
1395 m_channel, | 1412 if (!newFFTModel->isOK()) { |
1396 m_windowType, | |
1397 m_windowSize, | |
1398 getWindowIncrement(), | |
1399 getFFTSize()); | |
1400 | |
1401 if (!newModel->isOK()) { | |
1402 QMessageBox::critical | 1413 QMessageBox::critical |
1403 (nullptr, tr("FFT cache failed"), | 1414 (nullptr, tr("FFT cache failed"), |
1404 tr("Failed to create the FFT model for this spectrogram.\n" | 1415 tr("Failed to create the FFT model for this spectrogram.\n" |
1405 "There may be insufficient memory or disc space to continue.")); | 1416 "There may be insufficient memory or disc space to continue.")); |
1406 delete newModel; | |
1407 delete m_fftModel; | |
1408 m_fftModel = nullptr; | |
1409 return; | 1417 return; |
1410 } | 1418 } |
1411 | 1419 |
1412 FFTModel *oldModel = m_fftModel; | 1420 ModelById::add(newFFTModel); |
1413 m_fftModel = newModel; | 1421 m_fftModel = newFFTModel->getId(); |
1414 | 1422 |
1415 bool createWholeCache = false; | 1423 bool createWholeCache = false; |
1416 checkCacheSpace(&m_peakCacheDivisor, &createWholeCache); | 1424 checkCacheSpace(&m_peakCacheDivisor, &createWholeCache); |
1417 | 1425 |
1418 if (createWholeCache) { | 1426 if (createWholeCache) { |
1419 m_wholeCache = new Dense3DModelPeakCache(m_fftModel, 1); | 1427 |
1420 m_peakCache = new Dense3DModelPeakCache(m_wholeCache, m_peakCacheDivisor); | 1428 auto whole = std::make_shared<Dense3DModelPeakCache>(m_fftModel, 1); |
1429 ModelById::add(whole); | |
1430 m_wholeCache = whole->getId(); | |
1431 | |
1432 auto peaks = std::make_shared<Dense3DModelPeakCache>(m_wholeCache, | |
1433 m_peakCacheDivisor); | |
1434 ModelById::add(peaks); | |
1435 m_peakCache = peaks->getId(); | |
1436 | |
1421 } else { | 1437 } else { |
1422 m_peakCache = new Dense3DModelPeakCache(m_fftModel, m_peakCacheDivisor); | 1438 |
1423 } | 1439 auto peaks = std::make_shared<Dense3DModelPeakCache>(m_fftModel, |
1424 | 1440 m_peakCacheDivisor); |
1425 emit sliceableModelReplaced(oldModel, m_fftModel); | 1441 ModelById::add(peaks); |
1426 delete oldModel; | 1442 m_peakCache = peaks->getId(); |
1443 } | |
1427 } | 1444 } |
1428 | 1445 |
1429 void | 1446 void |
1430 SpectrogramLayer::checkCacheSpace(int *suggestedPeakDivisor, | 1447 SpectrogramLayer::checkCacheSpace(int *suggestedPeakDivisor, |
1431 bool *createWholeCache) const | 1448 bool *createWholeCache) const |
1432 { | 1449 { |
1433 *suggestedPeakDivisor = 8; | 1450 *suggestedPeakDivisor = 8; |
1434 *createWholeCache = false; | 1451 *createWholeCache = false; |
1435 | 1452 |
1436 if (!m_fftModel) return; | 1453 auto fftModel = ModelById::getAs<FFTModel>(m_fftModel); |
1454 if (!fftModel) return; | |
1437 | 1455 |
1438 size_t sz = | 1456 size_t sz = |
1439 size_t(m_fftModel->getWidth()) * | 1457 size_t(fftModel->getWidth()) * |
1440 size_t(m_fftModel->getHeight()) * | 1458 size_t(fftModel->getHeight()) * |
1441 sizeof(float); | 1459 sizeof(float); |
1442 | 1460 |
1443 try { | 1461 try { |
1444 SVDEBUG << "Requesting advice from StorageAdviser on whether to create whole-model cache" << endl; | 1462 SVDEBUG << "Requesting advice from StorageAdviser on whether to create whole-model cache" << endl; |
1445 // The lower amount here is the amount required for the | 1463 // The lower amount here is the amount required for the |
1465 } catch (const InsufficientDiscSpace &) { | 1483 } catch (const InsufficientDiscSpace &) { |
1466 SVDEBUG << "Seems like a terrible idea to create whole-model cache" << endl; | 1484 SVDEBUG << "Seems like a terrible idea to create whole-model cache" << endl; |
1467 } | 1485 } |
1468 } | 1486 } |
1469 | 1487 |
1470 const Model * | 1488 ModelId |
1471 SpectrogramLayer::getSliceableModel() const | 1489 SpectrogramLayer::getSliceableModel() const |
1472 { | 1490 { |
1473 return m_fftModel; | 1491 return m_fftModel; |
1474 } | 1492 } |
1475 | 1493 |
1495 | 1513 |
1496 if (m_renderers.find(viewId) == m_renderers.end()) { | 1514 if (m_renderers.find(viewId) == m_renderers.end()) { |
1497 | 1515 |
1498 Colour3DPlotRenderer::Sources sources; | 1516 Colour3DPlotRenderer::Sources sources; |
1499 sources.verticalBinLayer = this; | 1517 sources.verticalBinLayer = this; |
1500 sources.fft = getFFTModel(); | 1518 sources.fft = m_fftModel; |
1501 sources.source = sources.fft; | 1519 sources.source = sources.fft; |
1502 if (m_peakCache) sources.peakCaches.push_back(m_peakCache); | 1520 if (!m_peakCache.isNone()) sources.peakCaches.push_back(m_peakCache); |
1503 if (m_wholeCache) sources.peakCaches.push_back(m_wholeCache); | 1521 if (!m_wholeCache.isNone()) sources.peakCaches.push_back(m_wholeCache); |
1504 | 1522 |
1505 ColourScale::Parameters cparams; | 1523 ColourScale::Parameters cparams; |
1506 cparams.colourMap = m_colourMap; | 1524 cparams.colourMap = m_colourMap; |
1507 cparams.scaleType = m_colourScale; | 1525 cparams.scaleType = m_colourScale; |
1508 cparams.multiple = m_colourScaleMultiple; | 1526 cparams.multiple = m_colourScaleMultiple; |
1634 cerr << "SpectrogramLayer::paint() entering: m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << endl; | 1652 cerr << "SpectrogramLayer::paint() entering: m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << endl; |
1635 | 1653 |
1636 cerr << "SpectrogramLayer::paint(): rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; | 1654 cerr << "SpectrogramLayer::paint(): rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; |
1637 #endif | 1655 #endif |
1638 | 1656 |
1639 if (!m_model || !m_model->isOK() || !m_model->isReady()) { | 1657 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1658 if (!model || !model->isOK() || !model->isReady()) { | |
1640 return; | 1659 return; |
1641 } | 1660 } |
1642 | 1661 |
1643 paintWithRenderer(v, paint, rect); | 1662 paintWithRenderer(v, paint, rect); |
1644 | 1663 |
1648 void | 1667 void |
1649 SpectrogramLayer::illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &paint) const | 1668 SpectrogramLayer::illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &paint) const |
1650 { | 1669 { |
1651 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); | 1670 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); |
1652 | 1671 |
1672 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); | |
1673 | |
1653 QPoint localPos; | 1674 QPoint localPos; |
1654 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) { | 1675 if (!v->shouldIlluminateLocalFeatures(this, localPos) || !model) { |
1655 return; | 1676 return; |
1656 } | 1677 } |
1657 | 1678 |
1658 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1679 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1659 cerr << "SpectrogramLayer: illuminateLocalFeatures(" | 1680 cerr << "SpectrogramLayer: illuminateLocalFeatures(" |
1707 } | 1728 } |
1708 | 1729 |
1709 int | 1730 int |
1710 SpectrogramLayer::getCompletion(LayerGeometryProvider *) const | 1731 SpectrogramLayer::getCompletion(LayerGeometryProvider *) const |
1711 { | 1732 { |
1712 if (!m_fftModel) return 100; | 1733 auto fftModel = ModelById::getAs<FFTModel>(m_fftModel); |
1713 int completion = m_fftModel->getCompletion(); | 1734 if (!fftModel) return 100; |
1735 int completion = fftModel->getCompletion(); | |
1714 #ifdef DEBUG_SPECTROGRAM_REPAINT | 1736 #ifdef DEBUG_SPECTROGRAM_REPAINT |
1715 cerr << "SpectrogramLayer::getCompletion: completion = " << completion << endl; | 1737 cerr << "SpectrogramLayer::getCompletion: completion = " << completion << endl; |
1716 #endif | 1738 #endif |
1717 return completion; | 1739 return completion; |
1718 } | 1740 } |
1719 | 1741 |
1720 QString | 1742 QString |
1721 SpectrogramLayer::getError(LayerGeometryProvider *) const | 1743 SpectrogramLayer::getError(LayerGeometryProvider *) const |
1722 { | 1744 { |
1723 if (!m_fftModel) return ""; | 1745 auto fftModel = ModelById::getAs<FFTModel>(m_fftModel); |
1724 return m_fftModel->getError(); | 1746 if (!fftModel) return ""; |
1747 return fftModel->getError(); | |
1725 } | 1748 } |
1726 | 1749 |
1727 bool | 1750 bool |
1728 SpectrogramLayer::getValueExtents(double &min, double &max, | 1751 SpectrogramLayer::getValueExtents(double &min, double &max, |
1729 bool &logarithmic, QString &unit) const | 1752 bool &logarithmic, QString &unit) const |
1730 { | 1753 { |
1731 if (!m_model) return false; | 1754 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1732 | 1755 if (!model) return false; |
1733 sv_samplerate_t sr = m_model->getSampleRate(); | 1756 |
1757 sv_samplerate_t sr = model->getSampleRate(); | |
1734 min = double(sr) / getFFTSize(); | 1758 min = double(sr) / getFFTSize(); |
1735 max = double(sr) / 2; | 1759 max = double(sr) / 2; |
1736 | 1760 |
1737 logarithmic = (m_binScale == BinScale::Log); | 1761 logarithmic = (m_binScale == BinScale::Log); |
1738 unit = "Hz"; | 1762 unit = "Hz"; |
1750 } | 1774 } |
1751 | 1775 |
1752 bool | 1776 bool |
1753 SpectrogramLayer::setDisplayExtents(double min, double max) | 1777 SpectrogramLayer::setDisplayExtents(double min, double max) |
1754 { | 1778 { |
1755 if (!m_model) return false; | 1779 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1780 if (!model) return false; | |
1756 | 1781 |
1757 // SVDEBUG << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << endl; | 1782 // SVDEBUG << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << endl; |
1758 | 1783 |
1759 if (min < 0) min = 0; | 1784 if (min < 0) min = 0; |
1760 if (max > m_model->getSampleRate()/2.0) max = m_model->getSampleRate()/2.0; | 1785 if (max > model->getSampleRate()/2.0) max = model->getSampleRate()/2.0; |
1761 | 1786 |
1762 int minf = int(lrint(min)); | 1787 int minf = int(lrint(min)); |
1763 int maxf = int(lrint(max)); | 1788 int maxf = int(lrint(max)); |
1764 | 1789 |
1765 if (m_minFrequency == minf && m_maxFrequency == maxf) return true; | 1790 if (m_minFrequency == minf && m_maxFrequency == maxf) return true; |
1830 bool | 1855 bool |
1831 SpectrogramLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint, | 1856 SpectrogramLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint, |
1832 QPoint cursorPos, | 1857 QPoint cursorPos, |
1833 vector<QRect> &extents) const | 1858 vector<QRect> &extents) const |
1834 { | 1859 { |
1860 // Qt 5.13 deprecates QFontMetrics::width(), but its suggested | |
1861 // replacement (horizontalAdvance) was only added in Qt 5.11 | |
1862 // which is too new for us | |
1863 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
1864 | |
1835 QRect vertical(cursorPos.x() - 12, 0, 12, v->getPaintHeight()); | 1865 QRect vertical(cursorPos.x() - 12, 0, 12, v->getPaintHeight()); |
1836 extents.push_back(vertical); | 1866 extents.push_back(vertical); |
1837 | 1867 |
1838 QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1); | 1868 QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1); |
1839 extents.push_back(horizontal); | 1869 extents.push_back(horizontal); |
1868 | 1898 |
1869 void | 1899 void |
1870 SpectrogramLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint, | 1900 SpectrogramLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint, |
1871 QPoint cursorPos) const | 1901 QPoint cursorPos) const |
1872 { | 1902 { |
1903 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); | |
1904 if (!model) return; | |
1905 | |
1873 paint.save(); | 1906 paint.save(); |
1874 | 1907 |
1875 int sw = getVerticalScaleWidth(v, m_haveDetailedScale, paint); | 1908 int sw = getVerticalScaleWidth(v, m_haveDetailedScale, paint); |
1876 | 1909 |
1877 QFont fn = paint.font(); | 1910 QFont fn = paint.font(); |
1884 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); | 1917 paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y()); |
1885 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->getPaintHeight()); | 1918 paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->getPaintHeight()); |
1886 | 1919 |
1887 double fundamental = getFrequencyForY(v, cursorPos.y()); | 1920 double fundamental = getFrequencyForY(v, cursorPos.y()); |
1888 | 1921 |
1889 PaintAssistant::drawVisibleText(v, paint, | 1922 PaintAssistant::drawVisibleText |
1890 sw + 2, | 1923 (v, paint, |
1891 cursorPos.y() - 2, | 1924 sw + 2, |
1892 QString("%1 Hz").arg(fundamental), | 1925 cursorPos.y() - 2, |
1893 PaintAssistant::OutlinedText); | 1926 QString("%1 Hz").arg(fundamental), |
1927 PaintAssistant::OutlinedText); | |
1894 | 1928 |
1895 if (Pitch::isFrequencyInMidiRange(fundamental)) { | 1929 if (Pitch::isFrequencyInMidiRange(fundamental)) { |
1896 QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental); | 1930 QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental); |
1897 PaintAssistant::drawVisibleText(v, paint, | 1931 PaintAssistant::drawVisibleText |
1898 sw + 2, | 1932 (v, paint, |
1899 cursorPos.y() + paint.fontMetrics().ascent() + 2, | 1933 sw + 2, |
1900 pitchLabel, | 1934 cursorPos.y() + paint.fontMetrics().ascent() + 2, |
1901 PaintAssistant::OutlinedText); | 1935 pitchLabel, |
1936 PaintAssistant::OutlinedText); | |
1902 } | 1937 } |
1903 | 1938 |
1904 sv_frame_t frame = v->getFrameForX(cursorPos.x()); | 1939 sv_frame_t frame = v->getFrameForX(cursorPos.x()); |
1905 RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate()); | 1940 RealTime rt = RealTime::frame2RealTime(frame, model->getSampleRate()); |
1906 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); | 1941 QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str()); |
1907 QString frameLabel = QString("%1").arg(frame); | 1942 QString frameLabel = QString("%1").arg(frame); |
1908 PaintAssistant::drawVisibleText(v, paint, | 1943 PaintAssistant::drawVisibleText |
1909 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, | 1944 (v, paint, |
1910 v->getPaintHeight() - 2, | 1945 cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2, |
1911 frameLabel, | 1946 v->getPaintHeight() - 2, |
1912 PaintAssistant::OutlinedText); | 1947 frameLabel, |
1913 PaintAssistant::drawVisibleText(v, paint, | 1948 PaintAssistant::OutlinedText); |
1914 cursorPos.x() + 2, | 1949 PaintAssistant::drawVisibleText |
1915 v->getPaintHeight() - 2, | 1950 (v, paint, |
1916 rtLabel, | 1951 cursorPos.x() + 2, |
1917 PaintAssistant::OutlinedText); | 1952 v->getPaintHeight() - 2, |
1953 rtLabel, | |
1954 PaintAssistant::OutlinedText); | |
1918 | 1955 |
1919 int harmonic = 2; | 1956 int harmonic = 2; |
1920 | 1957 |
1921 while (harmonic < 100) { | 1958 while (harmonic < 100) { |
1922 | 1959 |
1948 SpectrogramLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const | 1985 SpectrogramLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const |
1949 { | 1986 { |
1950 int x = pos.x(); | 1987 int x = pos.x(); |
1951 int y = pos.y(); | 1988 int y = pos.y(); |
1952 | 1989 |
1953 if (!m_model || !m_model->isOK()) return ""; | 1990 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
1991 if (!model || !model->isOK()) return ""; | |
1954 | 1992 |
1955 double magMin = 0, magMax = 0; | 1993 double magMin = 0, magMax = 0; |
1956 double phaseMin = 0, phaseMax = 0; | 1994 double phaseMin = 0, phaseMax = 0; |
1957 double freqMin = 0, freqMax = 0; | 1995 double freqMin = 0, freqMax = 0; |
1958 double adjFreqMin = 0, adjFreqMax = 0; | 1996 double adjFreqMin = 0, adjFreqMax = 0; |
2067 } | 2105 } |
2068 | 2106 |
2069 int | 2107 int |
2070 SpectrogramLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &paint) const | 2108 SpectrogramLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &paint) const |
2071 { | 2109 { |
2072 if (!m_model || !m_model->isOK()) return 0; | 2110 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
2111 if (!model || !model->isOK()) return 0; | |
2073 | 2112 |
2074 int cw = 0; | 2113 int cw = 0; |
2075 if (detailed) cw = getColourScaleWidth(paint); | 2114 if (detailed) cw = getColourScaleWidth(paint); |
2076 | 2115 |
2077 int tw = paint.fontMetrics().width(QString("%1") | 2116 int tw = paint.fontMetrics().width(QString("%1") |
2078 .arg(m_maxFrequency > 0 ? | 2117 .arg(m_maxFrequency > 0 ? |
2079 m_maxFrequency - 1 : | 2118 m_maxFrequency - 1 : |
2080 m_model->getSampleRate() / 2)); | 2119 model->getSampleRate() / 2)); |
2081 | 2120 |
2082 int fw = paint.fontMetrics().width(tr("43Hz")); | 2121 int fw = paint.fontMetrics().width(tr("43Hz")); |
2083 if (tw < fw) tw = fw; | 2122 if (tw < fw) tw = fw; |
2084 | 2123 |
2085 int tickw = (m_binScale == BinScale::Log ? 10 : 4); | 2124 int tickw = (m_binScale == BinScale::Log ? 10 : 4); |
2089 | 2128 |
2090 void | 2129 void |
2091 SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed, | 2130 SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed, |
2092 QPainter &paint, QRect rect) const | 2131 QPainter &paint, QRect rect) const |
2093 { | 2132 { |
2094 if (!m_model || !m_model->isOK()) { | 2133 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
2134 if (!model || !model->isOK()) { | |
2095 return; | 2135 return; |
2096 } | 2136 } |
2097 | 2137 |
2098 Profiler profiler("SpectrogramLayer::paintVerticalScale"); | 2138 Profiler profiler("SpectrogramLayer::paintVerticalScale"); |
2099 | 2139 |
2109 | 2149 |
2110 int tickw = (m_binScale == BinScale::Log ? 10 : 4); | 2150 int tickw = (m_binScale == BinScale::Log ? 10 : 4); |
2111 int pkw = (m_binScale == BinScale::Log ? 10 : 0); | 2151 int pkw = (m_binScale == BinScale::Log ? 10 : 0); |
2112 | 2152 |
2113 int bins = getFFTSize() / 2; | 2153 int bins = getFFTSize() / 2; |
2114 sv_samplerate_t sr = m_model->getSampleRate(); | 2154 sv_samplerate_t sr = model->getSampleRate(); |
2115 | 2155 |
2116 if (m_maxFrequency > 0) { | 2156 if (m_maxFrequency > 0) { |
2117 bins = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1); | 2157 bins = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1); |
2118 if (bins > getFFTSize() / 2) bins = getFFTSize() / 2; | 2158 if (bins > getFFTSize() / 2) bins = getFFTSize() / 2; |
2119 } | 2159 } |
2379 }; | 2419 }; |
2380 | 2420 |
2381 int | 2421 int |
2382 SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const | 2422 SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const |
2383 { | 2423 { |
2384 if (!m_model) return 0; | 2424 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
2385 | 2425 if (!model) return 0; |
2386 sv_samplerate_t sr = m_model->getSampleRate(); | 2426 |
2427 sv_samplerate_t sr = model->getSampleRate(); | |
2387 | 2428 |
2388 SpectrogramRangeMapper mapper(sr, getFFTSize()); | 2429 SpectrogramRangeMapper mapper(sr, getFFTSize()); |
2389 | 2430 |
2390 // int maxStep = mapper.getPositionForValue((double(sr) / getFFTSize()) + 0.001); | 2431 // int maxStep = mapper.getPositionForValue((double(sr) / getFFTSize()) + 0.001); |
2391 int maxStep = mapper.getPositionForValue(0); | 2432 int maxStep = mapper.getPositionForValue(0); |
2402 } | 2443 } |
2403 | 2444 |
2404 int | 2445 int |
2405 SpectrogramLayer::getCurrentVerticalZoomStep() const | 2446 SpectrogramLayer::getCurrentVerticalZoomStep() const |
2406 { | 2447 { |
2407 if (!m_model) return 0; | 2448 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
2449 if (!model) return 0; | |
2408 | 2450 |
2409 double dmin, dmax; | 2451 double dmin, dmax; |
2410 getDisplayExtents(dmin, dmax); | 2452 getDisplayExtents(dmin, dmax); |
2411 | 2453 |
2412 SpectrogramRangeMapper mapper(m_model->getSampleRate(), getFFTSize()); | 2454 SpectrogramRangeMapper mapper(model->getSampleRate(), getFFTSize()); |
2413 int n = mapper.getPositionForValue(dmax - dmin); | 2455 int n = mapper.getPositionForValue(dmax - dmin); |
2414 // SVDEBUG << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << endl; | 2456 // SVDEBUG << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << endl; |
2415 return n; | 2457 return n; |
2416 } | 2458 } |
2417 | 2459 |
2418 void | 2460 void |
2419 SpectrogramLayer::setVerticalZoomStep(int step) | 2461 SpectrogramLayer::setVerticalZoomStep(int step) |
2420 { | 2462 { |
2421 if (!m_model) return; | 2463 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
2464 if (!model) return; | |
2422 | 2465 |
2423 double dmin = m_minFrequency, dmax = m_maxFrequency; | 2466 double dmin = m_minFrequency, dmax = m_maxFrequency; |
2424 // getDisplayExtents(dmin, dmax); | 2467 // getDisplayExtents(dmin, dmax); |
2425 | 2468 |
2426 // cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << endl; | 2469 // cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << endl; |
2427 | 2470 |
2428 sv_samplerate_t sr = m_model->getSampleRate(); | 2471 sv_samplerate_t sr = model->getSampleRate(); |
2429 SpectrogramRangeMapper mapper(sr, getFFTSize()); | 2472 SpectrogramRangeMapper mapper(sr, getFFTSize()); |
2430 double newdist = mapper.getValueForPosition(step); | 2473 double newdist = mapper.getValueForPosition(step); |
2431 | 2474 |
2432 double newmin, newmax; | 2475 double newmin, newmax; |
2433 | 2476 |
2484 } | 2527 } |
2485 | 2528 |
2486 RangeMapper * | 2529 RangeMapper * |
2487 SpectrogramLayer::getNewVerticalZoomRangeMapper() const | 2530 SpectrogramLayer::getNewVerticalZoomRangeMapper() const |
2488 { | 2531 { |
2489 if (!m_model) return nullptr; | 2532 auto model = ModelById::getAs<DenseTimeValueModel>(m_model); |
2490 return new SpectrogramRangeMapper(m_model->getSampleRate(), getFFTSize()); | 2533 if (!model) return nullptr; |
2534 return new SpectrogramRangeMapper(model->getSampleRate(), getFFTSize()); | |
2491 } | 2535 } |
2492 | 2536 |
2493 void | 2537 void |
2494 SpectrogramLayer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const | 2538 SpectrogramLayer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const |
2495 { | 2539 { |