Chris@545: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@545: Chris@545: /* Chris@545: Sonic Visualiser Chris@545: An audio file viewer and annotation editor. Chris@545: Centre for Digital Music, Queen Mary, University of London. Chris@545: This file copyright 2009 QMUL. Chris@545: Chris@545: This program is free software; you can redistribute it and/or Chris@545: modify it under the terms of the GNU General Public License as Chris@545: published by the Free Software Foundation; either version 2 of the Chris@545: License, or (at your option) any later version. See the file Chris@545: COPYING included with this distribution for more information. Chris@545: */ Chris@545: Chris@545: #include "Dense3DModelPeakCache.h" Chris@545: Chris@551: #include "base/Profiler.h" Chris@551: Chris@1340: #include "base/HitCount.h" Chris@1340: Chris@1191: Dense3DModelPeakCache::Dense3DModelPeakCache(const DenseThreeDimensionalModel *source, Chris@1429: int columnsPerPeak) : Chris@545: m_source(source), Chris@1190: m_columnsPerPeak(columnsPerPeak) Chris@545: { Chris@545: m_cache = new EditableDenseThreeDimensionalModel Chris@545: (source->getSampleRate(), Chris@545: getResolution(), Chris@545: source->getHeight(), Chris@545: EditableDenseThreeDimensionalModel::NoCompression, Chris@545: false); Chris@545: Chris@545: connect(source, SIGNAL(modelChanged()), Chris@545: this, SLOT(sourceModelChanged())); Chris@546: connect(source, SIGNAL(aboutToBeDeleted()), Chris@545: this, SLOT(sourceModelAboutToBeDeleted())); Chris@545: } Chris@545: Chris@545: Dense3DModelPeakCache::~Dense3DModelPeakCache() Chris@545: { Chris@1384: if (m_cache) m_cache->aboutToDelete(); Chris@545: delete m_cache; Chris@545: } Chris@545: Chris@545: Dense3DModelPeakCache::Column Chris@929: Dense3DModelPeakCache::getColumn(int column) const Chris@545: { Chris@545: if (!m_source) return Column(); Chris@545: if (!haveColumn(column)) fillColumn(column); Chris@545: return m_cache->getColumn(column); Chris@545: } Chris@545: Chris@545: float Chris@929: Dense3DModelPeakCache::getValueAt(int column, int n) const Chris@545: { Chris@545: if (!m_source) return 0.f; Chris@545: if (!haveColumn(column)) fillColumn(column); Chris@545: return m_cache->getValueAt(column, n); Chris@545: } Chris@545: Chris@545: void Chris@545: Dense3DModelPeakCache::sourceModelChanged() Chris@545: { Chris@545: if (!m_source) return; Chris@546: if (m_coverage.size() > 0) { Chris@546: // The last peak may have come from an incomplete read, which Chris@546: // may since have been filled, so reset it Chris@1153: m_coverage[m_coverage.size()-1] = false; Chris@546: } Chris@1153: m_coverage.resize(getWidth(), false); // retaining data Chris@545: } Chris@545: Chris@545: void Chris@545: Dense3DModelPeakCache::sourceModelAboutToBeDeleted() Chris@545: { Chris@1582: m_source = nullptr; Chris@545: } Chris@545: Chris@545: bool Chris@929: Dense3DModelPeakCache::haveColumn(int column) const Chris@545: { Chris@1340: static HitCount count("Dense3DModelPeakCache"); Chris@1340: if (in_range_for(m_coverage, column) && m_coverage[column]) { Chris@1340: count.hit(); Chris@1340: return true; Chris@1340: } else { Chris@1340: count.miss(); Chris@1340: return false; Chris@1340: } Chris@545: } Chris@545: Chris@545: void Chris@929: Dense3DModelPeakCache::fillColumn(int column) const Chris@545: { Chris@551: Profiler profiler("Dense3DModelPeakCache::fillColumn"); Chris@551: Chris@1153: if (!in_range_for(m_coverage, column)) { Chris@1192: if (m_coverage.size() > 0) { Chris@1192: // The last peak may have come from an incomplete read, which Chris@1192: // may since have been filled, so reset it Chris@1192: m_coverage[m_coverage.size()-1] = false; Chris@1192: } Chris@1153: m_coverage.resize(column + 1, false); Chris@551: } Chris@546: Chris@1192: int sourceWidth = m_source->getWidth(); Chris@1192: Chris@545: Column peak; Chris@1156: int n = 0; Chris@1190: for (int i = 0; i < m_columnsPerPeak; ++i) { Chris@1192: Chris@1192: int sourceColumn = column * m_columnsPerPeak + i; Chris@1192: if (sourceColumn >= sourceWidth) break; Chris@1192: Chris@1192: Column here = m_source->getColumn(sourceColumn); Chris@1192: Chris@1192: // cerr << "Dense3DModelPeakCache::fillColumn(" << column << "): source col " Chris@1192: // << sourceColumn << " of " << sourceWidth Chris@1192: // << " returned " << here.size() << " elts" << endl; Chris@1192: Chris@545: if (i == 0) { Chris@545: peak = here; Chris@1156: n = int(peak.size()); Chris@545: } else { Chris@1156: int m = std::min(n, int(here.size())); Chris@1156: for (int j = 0; j < m; ++j) { Chris@1156: peak[j] = std::max(here[j], peak[j]); Chris@545: } Chris@545: } Chris@545: } Chris@546: Chris@545: m_cache->setColumn(column, peak); Chris@1153: m_coverage[column] = true; Chris@545: } Chris@545: Chris@545: