comparison layer/SpectrogramLayer.cpp @ 1486:ac0a8addabcf

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