diff 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
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Mon Jul 01 14:25:53 2019 +0100
+++ b/layer/SpectrogramLayer.cpp	Tue Jul 02 11:49:52 2019 +0100
@@ -82,8 +82,6 @@
     m_synchronous(false),
     m_haveDetailedScale(false),
     m_exiting(false),
-    m_wholeCache(nullptr),
-    m_peakCache(nullptr),
     m_peakCacheDivisor(8)
 {
     QString colourConfigName = "spectrogram-colour";
@@ -138,17 +136,13 @@
 void
 SpectrogramLayer::deleteDerivedModels()
 {
-    if (m_fftModel) m_fftModel->aboutToDelete();
-    if (m_peakCache) m_peakCache->aboutToDelete();
-    if (m_wholeCache) m_wholeCache->aboutToDelete();
-
-    delete m_fftModel;
-    delete m_peakCache;
-    delete m_wholeCache;
-
-    m_fftModel = nullptr;
-    m_peakCache = nullptr;
-    m_wholeCache = nullptr;
+    ModelById::release(m_fftModel);
+    ModelById::release(m_peakCache);
+    ModelById::release(m_wholeCache);
+
+    m_fftModel = {};
+    m_peakCache = {};
+    m_wholeCache = {};
 }
 
 pair<ColourScaleType, double>
@@ -1107,7 +1101,10 @@
 double
 SpectrogramLayer::getEffectiveMinFrequency() const
 {
-    sv_samplerate_t sr = m_model->getSampleRate();
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return 0.0;
+    
+    sv_samplerate_t sr = model->getSampleRate();
     double minf = double(sr) / getFFTSize();
 
     if (m_minFrequency > 0.0) {
@@ -1122,7 +1119,10 @@
 double
 SpectrogramLayer::getEffectiveMaxFrequency() const
 {
-    sv_samplerate_t sr = m_model->getSampleRate();
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return 0.0;
+    
+    sv_samplerate_t sr = model->getSampleRate();
     double maxf = double(sr) / 2;
 
     if (m_maxFrequency > 0.0) {
@@ -1148,10 +1148,13 @@
 double
 SpectrogramLayer::getYForBin(const LayerGeometryProvider *v, double bin) const
 {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return 0.0;
+    
     double minf = getEffectiveMinFrequency();
     double maxf = getEffectiveMaxFrequency();
     bool logarithmic = (m_binScale == BinScale::Log);
-    sv_samplerate_t sr = m_model->getSampleRate();
+    sv_samplerate_t sr = model->getSampleRate();
 
     double freq = (bin * sr) / getFFTSize();
     
@@ -1163,7 +1166,10 @@
 double
 SpectrogramLayer::getBinForY(const LayerGeometryProvider *v, double y) const
 {
-    sv_samplerate_t sr = m_model->getSampleRate();
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return 0.0;
+
+    sv_samplerate_t sr = model->getSampleRate();
     double minf = getEffectiveMinFrequency();
     double maxf = getEffectiveMaxFrequency();
 
@@ -1180,8 +1186,11 @@
 bool
 SpectrogramLayer::getXBinRange(LayerGeometryProvider *v, int x, double &s0, double &s1) const
 {
-    sv_frame_t modelStart = m_model->getStartFrame();
-    sv_frame_t modelEnd = m_model->getEndFrame();
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return false;
+
+    sv_frame_t modelStart = model->getStartFrame();
+    sv_frame_t modelEnd = model->getEndFrame();
 
     // Each pixel column covers an exact range of sample frames:
     sv_frame_t f0 = v->getFrameForX(x) - modelStart;
@@ -1204,6 +1213,9 @@
 bool
 SpectrogramLayer::getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &min, RealTime &max) const
 {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return false;
+
     double s0 = 0, s1 = 0;
     if (!getXBinRange(v, x, s0, s1)) return false;
     
@@ -1215,8 +1227,8 @@
     int w1 = s1i * windowIncrement + windowIncrement +
         (m_windowSize - windowIncrement)/2 - 1;
     
-    min = RealTime::frame2RealTime(w0, m_model->getSampleRate());
-    max = RealTime::frame2RealTime(w1, m_model->getSampleRate());
+    min = RealTime::frame2RealTime(w0, model->getSampleRate());
+    max = RealTime::frame2RealTime(w1, model->getSampleRate());
     return true;
 }
 
@@ -1224,13 +1236,16 @@
 SpectrogramLayer::getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax)
 const
 {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return false;
+
     double q0 = 0, q1 = 0;
     if (!getYBinRange(v, y, q0, q1)) return false;
 
     int q0i = int(q0 + 0.001);
     int q1i = int(q1);
 
-    sv_samplerate_t sr = m_model->getSampleRate();
+    sv_samplerate_t sr = model->getSampleRate();
 
     for (int q = q0i; q <= q1i; ++q) {
         if (q == q0i) freqMin = (sr * q) / getFFTSize();
@@ -1245,11 +1260,12 @@
                                              double &adjFreqMin, double &adjFreqMax)
 const
 {
-    if (!m_model || !m_model->isOK() || !m_model->isReady()) {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model || !model->isOK() || !model->isReady()) {
         return false;
     }
 
-    FFTModel *fft = getFFTModel();
+    auto fft = ModelById::getAs<FFTModel>(m_fftModel);
     if (!fft) return false;
 
     double s0 = 0, s1 = 0;
@@ -1264,7 +1280,7 @@
     int q0i = int(q0 + 0.001);
     int q1i = int(q1);
 
-    sv_samplerate_t sr = m_model->getSampleRate();
+    sv_samplerate_t sr = model->getSampleRate();
 
     bool haveAdj = false;
 
@@ -1312,7 +1328,8 @@
                                       double &min, double &max,
                                       double &phaseMin, double &phaseMax) const
 {
-    if (!m_model || !m_model->isOK() || !m_model->isReady()) {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model || !model->isOK() || !model->isReady()) {
         return false;
     }
 
@@ -1330,7 +1347,7 @@
 
     bool rv = false;
 
-    FFTModel *fft = getFFTModel();
+    auto fft = ModelById::getAs<FFTModel>(m_fftModel);
 
     if (fft) {
 
@@ -1375,55 +1392,55 @@
 {
     SVDEBUG << "SpectrogramLayer::recreateFFTModel called" << endl;
 
-    if (!m_model || !m_model->isOK()) {
-        emit sliceableModelReplaced(m_fftModel, nullptr);
-        deleteDerivedModels();
-        return;
+    { // scope, avoid hanging on to this pointer
+        auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+        if (!model || !model->isOK()) {
+            deleteDerivedModels();
+            return;
+        }
     }
-
-    if (m_fftModel) m_fftModel->aboutToDelete();
     
-    if (m_peakCache) m_peakCache->aboutToDelete();
-    delete m_peakCache;
-    m_peakCache = nullptr;
-
-    if (m_wholeCache) m_wholeCache->aboutToDelete();
-    delete m_wholeCache;
-    m_wholeCache = nullptr;
-    
-    FFTModel *newModel = new FFTModel(m_model,
-                                      m_channel,
-                                      m_windowType,
-                                      m_windowSize,
-                                      getWindowIncrement(),
-                                      getFFTSize());
-
-    if (!newModel->isOK()) {
+    deleteDerivedModels();
+
+    auto newFFTModel = std::make_shared<FFTModel>(m_model,
+                                                  m_channel,
+                                                  m_windowType,
+                                                  m_windowSize,
+                                                  getWindowIncrement(),
+                                                  getFFTSize());
+
+    if (!newFFTModel->isOK()) {
         QMessageBox::critical
             (nullptr, tr("FFT cache failed"),
              tr("Failed to create the FFT model for this spectrogram.\n"
                 "There may be insufficient memory or disc space to continue."));
-        delete newModel;
-        delete m_fftModel;
-        m_fftModel = nullptr;
         return;
     }
 
-    FFTModel *oldModel = m_fftModel;
-    m_fftModel = newModel;
+    ModelById::add(newFFTModel);
+    m_fftModel = newFFTModel->getId();
 
     bool createWholeCache = false;
     checkCacheSpace(&m_peakCacheDivisor, &createWholeCache);
     
     if (createWholeCache) {
-        m_wholeCache = new Dense3DModelPeakCache(m_fftModel, 1);
-        m_peakCache = new Dense3DModelPeakCache(m_wholeCache, m_peakCacheDivisor);
+
+        auto whole = std::make_shared<Dense3DModelPeakCache>(m_fftModel, 1);
+        ModelById::add(whole);
+        m_wholeCache = whole->getId();
+
+        auto peaks = std::make_shared<Dense3DModelPeakCache>(m_wholeCache,
+                                                             m_peakCacheDivisor);
+        ModelById::add(peaks);
+        m_peakCache = peaks->getId();
+
     } else {
-        m_peakCache = new Dense3DModelPeakCache(m_fftModel, m_peakCacheDivisor);
+
+        auto peaks = std::make_shared<Dense3DModelPeakCache>(m_fftModel,
+                                                             m_peakCacheDivisor);
+        ModelById::add(peaks);
+        m_peakCache = peaks->getId();
     }
-
-    emit sliceableModelReplaced(oldModel, m_fftModel);
-    delete oldModel;
 }
 
 void
@@ -1432,12 +1449,13 @@
 {
     *suggestedPeakDivisor = 8;
     *createWholeCache = false;
-    
-    if (!m_fftModel) return;
+
+    auto fftModel = ModelById::getAs<FFTModel>(m_fftModel);
+    if (!fftModel) return;
 
     size_t sz =
-        size_t(m_fftModel->getWidth()) *
-        size_t(m_fftModel->getHeight()) *
+        size_t(fftModel->getWidth()) *
+        size_t(fftModel->getHeight()) *
         sizeof(float);
 
     try {
@@ -1467,7 +1485,7 @@
     }
 }
 
-const Model *
+ModelId
 SpectrogramLayer::getSliceableModel() const
 {
     return m_fftModel;
@@ -1497,10 +1515,10 @@
 
         Colour3DPlotRenderer::Sources sources;
         sources.verticalBinLayer = this;
-        sources.fft = getFFTModel();
+        sources.fft = m_fftModel;
         sources.source = sources.fft;
-        if (m_peakCache) sources.peakCaches.push_back(m_peakCache);
-        if (m_wholeCache) sources.peakCaches.push_back(m_wholeCache);
+        if (!m_peakCache.isNone()) sources.peakCaches.push_back(m_peakCache);
+        if (!m_wholeCache.isNone()) sources.peakCaches.push_back(m_wholeCache);
 
         ColourScale::Parameters cparams;
         cparams.colourMap = m_colourMap;
@@ -1636,7 +1654,8 @@
     cerr << "SpectrogramLayer::paint(): rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
 #endif
 
-    if (!m_model || !m_model->isOK() || !m_model->isReady()) {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model || !model->isOK() || !model->isReady()) {
         return;
     }
 
@@ -1650,8 +1669,10 @@
 {
     Profiler profiler("SpectrogramLayer::illuminateLocalFeatures");
 
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    
     QPoint localPos;
-    if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) {
+    if (!v->shouldIlluminateLocalFeatures(this, localPos) || !model) {
         return;
     }
 
@@ -1709,8 +1730,9 @@
 int
 SpectrogramLayer::getCompletion(LayerGeometryProvider *) const
 {
-    if (!m_fftModel) return 100;
-    int completion = m_fftModel->getCompletion();
+    auto fftModel = ModelById::getAs<FFTModel>(m_fftModel);
+    if (!fftModel) return 100;
+    int completion = fftModel->getCompletion();
 #ifdef DEBUG_SPECTROGRAM_REPAINT
     cerr << "SpectrogramLayer::getCompletion: completion = " << completion << endl;
 #endif
@@ -1720,17 +1742,19 @@
 QString
 SpectrogramLayer::getError(LayerGeometryProvider *) const
 {
-    if (!m_fftModel) return "";
-    return m_fftModel->getError();
+    auto fftModel = ModelById::getAs<FFTModel>(m_fftModel);
+    if (!fftModel) return "";
+    return fftModel->getError();
 }
 
 bool
 SpectrogramLayer::getValueExtents(double &min, double &max,
                                   bool &logarithmic, QString &unit) const
 {
-    if (!m_model) return false;
-
-    sv_samplerate_t sr = m_model->getSampleRate();
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return false;
+
+    sv_samplerate_t sr = model->getSampleRate();
     min = double(sr) / getFFTSize();
     max = double(sr) / 2;
     
@@ -1752,12 +1776,13 @@
 bool
 SpectrogramLayer::setDisplayExtents(double min, double max)
 {
-    if (!m_model) return false;
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return false;
 
 //    SVDEBUG << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << endl;
 
     if (min < 0) min = 0;
-    if (max > m_model->getSampleRate()/2.0) max = m_model->getSampleRate()/2.0;
+    if (max > model->getSampleRate()/2.0) max = model->getSampleRate()/2.0;
     
     int minf = int(lrint(min));
     int maxf = int(lrint(max));
@@ -1832,6 +1857,11 @@
                                       QPoint cursorPos,
                                       vector<QRect> &extents) const
 {
+    // Qt 5.13 deprecates QFontMetrics::width(), but its suggested
+    // replacement (horizontalAdvance) was only added in Qt 5.11
+    // which is too new for us
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
     QRect vertical(cursorPos.x() - 12, 0, 12, v->getPaintHeight());
     extents.push_back(vertical);
 
@@ -1870,6 +1900,9 @@
 SpectrogramLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint,
                                   QPoint cursorPos) const
 {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return;
+
     paint.save();
     
     int sw = getVerticalScaleWidth(v, m_haveDetailedScale, paint);
@@ -1886,35 +1919,39 @@
     
     double fundamental = getFrequencyForY(v, cursorPos.y());
 
-    PaintAssistant::drawVisibleText(v, paint,
-                       sw + 2,
-                       cursorPos.y() - 2,
-                       QString("%1 Hz").arg(fundamental),
-                       PaintAssistant::OutlinedText);
+    PaintAssistant::drawVisibleText
+        (v, paint,
+         sw + 2,
+         cursorPos.y() - 2,
+         QString("%1 Hz").arg(fundamental),
+         PaintAssistant::OutlinedText);
 
     if (Pitch::isFrequencyInMidiRange(fundamental)) {
         QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental);
-        PaintAssistant::drawVisibleText(v, paint,
-                           sw + 2,
-                           cursorPos.y() + paint.fontMetrics().ascent() + 2,
-                           pitchLabel,
-                           PaintAssistant::OutlinedText);
+        PaintAssistant::drawVisibleText
+            (v, paint,
+             sw + 2,
+             cursorPos.y() + paint.fontMetrics().ascent() + 2,
+             pitchLabel,
+             PaintAssistant::OutlinedText);
     }
 
     sv_frame_t frame = v->getFrameForX(cursorPos.x());
-    RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate());
+    RealTime rt = RealTime::frame2RealTime(frame, model->getSampleRate());
     QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str());
     QString frameLabel = QString("%1").arg(frame);
-    PaintAssistant::drawVisibleText(v, paint,
-                       cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2,
-                       v->getPaintHeight() - 2,
-                       frameLabel,
-                       PaintAssistant::OutlinedText);
-    PaintAssistant::drawVisibleText(v, paint,
-                       cursorPos.x() + 2,
-                       v->getPaintHeight() - 2,
-                       rtLabel,
-                       PaintAssistant::OutlinedText);
+    PaintAssistant::drawVisibleText
+        (v, paint,
+         cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2,
+         v->getPaintHeight() - 2,
+         frameLabel,
+         PaintAssistant::OutlinedText);
+    PaintAssistant::drawVisibleText
+        (v, paint,
+         cursorPos.x() + 2,
+         v->getPaintHeight() - 2,
+         rtLabel,
+         PaintAssistant::OutlinedText);
 
     int harmonic = 2;
 
@@ -1950,7 +1987,8 @@
     int x = pos.x();
     int y = pos.y();
 
-    if (!m_model || !m_model->isOK()) return "";
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model || !model->isOK()) return "";
 
     double magMin = 0, magMax = 0;
     double phaseMin = 0, phaseMax = 0;
@@ -2069,7 +2107,8 @@
 int
 SpectrogramLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool detailed, QPainter &paint) const
 {
-    if (!m_model || !m_model->isOK()) return 0;
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model || !model->isOK()) return 0;
 
     int cw = 0;
     if (detailed) cw = getColourScaleWidth(paint);
@@ -2077,7 +2116,7 @@
     int tw = paint.fontMetrics().width(QString("%1")
                                      .arg(m_maxFrequency > 0 ?
                                           m_maxFrequency - 1 :
-                                          m_model->getSampleRate() / 2));
+                                          model->getSampleRate() / 2));
 
     int fw = paint.fontMetrics().width(tr("43Hz"));
     if (tw < fw) tw = fw;
@@ -2091,7 +2130,8 @@
 SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed,
                                      QPainter &paint, QRect rect) const
 {
-    if (!m_model || !m_model->isOK()) {
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model || !model->isOK()) {
         return;
     }
 
@@ -2111,7 +2151,7 @@
     int pkw = (m_binScale == BinScale::Log ? 10 : 0);
 
     int bins = getFFTSize() / 2;
-    sv_samplerate_t sr = m_model->getSampleRate();
+    sv_samplerate_t sr = model->getSampleRate();
 
     if (m_maxFrequency > 0) {
         bins = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1);
@@ -2381,9 +2421,10 @@
 int
 SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const
 {
-    if (!m_model) return 0;
-
-    sv_samplerate_t sr = m_model->getSampleRate();
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return 0;
+
+    sv_samplerate_t sr = model->getSampleRate();
 
     SpectrogramRangeMapper mapper(sr, getFFTSize());
 
@@ -2404,12 +2445,13 @@
 int
 SpectrogramLayer::getCurrentVerticalZoomStep() const
 {
-    if (!m_model) return 0;
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return 0;
 
     double dmin, dmax;
     getDisplayExtents(dmin, dmax);
     
-    SpectrogramRangeMapper mapper(m_model->getSampleRate(), getFFTSize());
+    SpectrogramRangeMapper mapper(model->getSampleRate(), getFFTSize());
     int n = mapper.getPositionForValue(dmax - dmin);
 //    SVDEBUG << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << endl;
     return n;
@@ -2418,14 +2460,15 @@
 void
 SpectrogramLayer::setVerticalZoomStep(int step)
 {
-    if (!m_model) return;
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return;
 
     double dmin = m_minFrequency, dmax = m_maxFrequency;
 //    getDisplayExtents(dmin, dmax);
 
 //    cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << endl;
     
-    sv_samplerate_t sr = m_model->getSampleRate();
+    sv_samplerate_t sr = model->getSampleRate();
     SpectrogramRangeMapper mapper(sr, getFFTSize());
     double newdist = mapper.getValueForPosition(step);
 
@@ -2486,8 +2529,9 @@
 RangeMapper *
 SpectrogramLayer::getNewVerticalZoomRangeMapper() const
 {
-    if (!m_model) return nullptr;
-    return new SpectrogramRangeMapper(m_model->getSampleRate(), getFFTSize());
+    auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
+    if (!model) return nullptr;
+    return new SpectrogramRangeMapper(model->getSampleRate(), getFFTSize());
 }
 
 void