# HG changeset patch # User Chris Cannam # Date 1568197167 -3600 # Node ID 59d9dcfd67c21eb543d8e27410954f87a830c979 # Parent d484490cdf6957e53d7cb9ddaedb036dd8341cfb 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 diff -r d484490cdf69 -r 59d9dcfd67c2 data/model/Dense3DModelPeakCache.cpp --- 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(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(m_source); + if (!source) { + return; + } + + int sourceWidth = source->getWidth(); + int sourceColumn = column * m_columnsPerPeak; + if (sourceColumn >= sourceWidth) { + return; } - auto source = ModelById::getAs(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; } diff -r d484490cdf69 -r 59d9dcfd67c2 data/model/Dense3DModelPeakCache.h --- 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 m_cache; - mutable std::vector m_coverage; // must be bool, for space efficiency - // (vector of bool uses 1-bit elements) int m_columnsPerPeak; + mutable std::vector> m_cache; + mutable std::vector 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; };