changeset 1778:59d9dcfd67c2

Replace the model used for the cache part of the peak-cache model with a simple vector of vectors. Avoids unnecessary locking in a class that is not thread-safe in any case. Also record whether the final column is actually truncated, rather than risk possible backward seeks to re-read it in the case where it simply might be
author Chris Cannam
date Wed, 11 Sep 2019 11:19:27 +0100
parents d484490cdf69
children 85903b0e9b42
files data/model/Dense3DModelPeakCache.cpp data/model/Dense3DModelPeakCache.h
diffstat 2 files changed, 48 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/data/model/Dense3DModelPeakCache.cpp	Tue Sep 10 16:34:47 2019 +0100
+++ b/data/model/Dense3DModelPeakCache.cpp	Wed Sep 11 11:19:27 2019 +0100
@@ -22,7 +22,8 @@
 Dense3DModelPeakCache::Dense3DModelPeakCache(ModelId sourceId,
                                              int columnsPerPeak) :
     m_source(sourceId),
-    m_columnsPerPeak(columnsPerPeak)
+    m_columnsPerPeak(columnsPerPeak),
+    m_finalColumnIncomplete(false)
 {
     auto source = ModelById::getAs<DenseThreeDimensionalModel>(m_source);
     if (!source) {
@@ -31,12 +32,6 @@
         return;
     }
 
-    m_cache.reset(new EditableDenseThreeDimensionalModel
-                  (source->getSampleRate(),
-                   source->getResolution() * m_columnsPerPeak,
-                   source->getHeight(),
-                   false));
-
     connect(source.get(), SIGNAL(modelChanged(ModelId)),
             this, SLOT(sourceModelChanged(ModelId)));
 }
@@ -49,25 +44,25 @@
 Dense3DModelPeakCache::getColumn(int column) const
 {
     if (!haveColumn(column)) fillColumn(column);
-    return m_cache->getColumn(column);
+    return m_cache.at(column);
 }
 
 float
 Dense3DModelPeakCache::getValueAt(int column, int n) const
 {
     if (!haveColumn(column)) fillColumn(column);
-    return m_cache->getValueAt(column, n);
+    return m_cache.at(column).at(n);
 }
 
 void
 Dense3DModelPeakCache::sourceModelChanged(ModelId)
 {
-    if (m_coverage.size() > 0) {
-        // The last peak may have come from an incomplete read, which
-        // may since have been filled, so reset it
+    if (m_finalColumnIncomplete && m_coverage.size() > 0) {
+        // The last peak came from an incomplete read, which may since
+        // have been filled, so reset it
         m_coverage[m_coverage.size()-1] = false;
+        m_finalColumnIncomplete = false;
     }
-    m_coverage.resize(getWidth(), false); // retaining data
 }
 
 bool
@@ -89,44 +84,46 @@
     Profiler profiler("Dense3DModelPeakCache::fillColumn");
 
     if (!in_range_for(m_coverage, column)) {
-        if (m_coverage.size() > 0) {
+        if (m_finalColumnIncomplete && m_coverage.size() > 0) {
             // The last peak may have come from an incomplete read, which
             // may since have been filled, so reset it
             m_coverage[m_coverage.size()-1] = false;
+            m_finalColumnIncomplete = false;
         }
         m_coverage.resize(column + 1, false);
+        m_cache.resize(column + 1, {});
+    }
+    
+    auto source = ModelById::getAs<DenseThreeDimensionalModel>(m_source);
+    if (!source) {
+        return;
+    }
+    
+    int sourceWidth = source->getWidth();
+    int sourceColumn = column * m_columnsPerPeak;
+    if (sourceColumn >= sourceWidth) {
+        return;
     }
 
-    auto source = ModelById::getAs<DenseThreeDimensionalModel>(m_source);
-    if (!source) return;
+    Column peak = source->getColumn(sourceColumn);
+    int n = int(peak.size());
     
-    int sourceWidth = source->getWidth();
-    
-    Column peak;
-    int n = 0;
-    for (int i = 0; i < m_columnsPerPeak; ++i) {
+    for (int i = 1; i < m_columnsPerPeak; ++i) {
 
-        int sourceColumn = column * m_columnsPerPeak + i;
-        if (sourceColumn >= sourceWidth) break;
+        ++sourceColumn;
+        if (sourceColumn >= sourceWidth) {
+            m_finalColumnIncomplete = true;
+            break;
+        }
         
         Column here = source->getColumn(sourceColumn);
-
-//        cerr << "Dense3DModelPeakCache::fillColumn(" << column << "): source col "
-//             << sourceColumn << " of " << sourceWidth
-//             << " returned " << here.size() << " elts" << endl;
-        
-        if (i == 0) {
-            peak = here;
-            n = int(peak.size());
-        } else {
-            int m = std::min(n, int(here.size()));
-            for (int j = 0; j < m; ++j) {
-                peak[j] = std::max(here[j], peak[j]);
-            }
+        int m = std::min(n, int(here.size()));
+        for (int j = 0; j < m; ++j) {
+            peak[j] = std::max(here[j], peak[j]);
         }
     }
 
-    m_cache->setColumn(column, peak);
+    m_cache[column] = peak;
     m_coverage[column] = true;
 }
 
--- a/data/model/Dense3DModelPeakCache.h	Tue Sep 10 16:34:47 2019 +0100
+++ b/data/model/Dense3DModelPeakCache.h	Wed Sep 11 11:19:27 2019 +0100
@@ -19,6 +19,15 @@
 #include "DenseThreeDimensionalModel.h"
 #include "EditableDenseThreeDimensionalModel.h"
 
+/**
+ * A DenseThreeDimensionalModel that represents a reduction in the
+ * time dimension of another DenseThreeDimensionalModel. Each column
+ * contains the peak values from a number of consecutive columns in
+ * the source. Each column is populated from the source model when
+ * first requested, and is returned from cache on subsequent requests.
+ *
+ * Dense3DModelPeakCache is not thread-safe.
+ */
 class Dense3DModelPeakCache : public DenseThreeDimensionalModel
 {
     Q_OBJECT
@@ -120,11 +129,13 @@
 
 private:
     ModelId m_source;
-    mutable std::unique_ptr<EditableDenseThreeDimensionalModel> m_cache;
-    mutable std::vector<bool> m_coverage; // must be bool, for space efficiency
-                                          // (vector of bool uses 1-bit elements)
     int m_columnsPerPeak;
 
+    mutable std::vector<std::vector<float>> m_cache;
+    mutable std::vector<bool> m_coverage; // bool for space efficiency
+                                          // (vector of bool is a bitmap)
+    mutable bool m_finalColumnIncomplete;
+
     bool haveColumn(int column) const;
     void fillColumn(int column) const;
 };