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@545: Dense3DModelPeakCache::Dense3DModelPeakCache(DenseThreeDimensionalModel *source, Chris@929: int columnsPerPeak) : Chris@545: m_source(source), Chris@545: m_resolution(columnsPerPeak) Chris@545: { Chris@546: m_coverage.resize(1); // otherwise it is simply invalid Chris@546: 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: Chris@545: Dense3DModelPeakCache::~Dense3DModelPeakCache() Chris@545: { Chris@545: delete m_cache; Chris@545: } Chris@545: Chris@545: bool Chris@929: Dense3DModelPeakCache::isColumnAvailable(int column) const Chris@545: { Chris@545: if (!m_source) return false; Chris@545: if (haveColumn(column)) return true; Chris@552: for (int i = m_resolution; i > 0; ) { Chris@552: --i; Chris@545: if (!m_source->isColumnAvailable(column * m_resolution + i)) { Chris@545: return false; Chris@545: } Chris@545: } Chris@545: return true; Chris@545: } Chris@545: Chris@545: Dense3DModelPeakCache::Column Chris@929: Dense3DModelPeakCache::getColumn(int column) const Chris@545: { Chris@551: Profiler profiler("Dense3DModelPeakCache::getColumn"); 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@546: m_coverage.reset(m_coverage.size()-1); Chris@546: } Chris@548: m_coverage.resize(getWidth()); // retaining data Chris@545: } Chris@545: Chris@545: void Chris@545: Dense3DModelPeakCache::sourceModelAboutToBeDeleted() Chris@545: { Chris@545: m_source = 0; Chris@545: } Chris@545: Chris@545: bool Chris@929: Dense3DModelPeakCache::haveColumn(int column) const Chris@545: { Chris@929: return column < (int)m_coverage.size() && m_coverage.get(column); 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@929: if (column >= (int)m_coverage.size()) { Chris@551: // see note in sourceModelChanged Chris@551: if (m_coverage.size() > 0) m_coverage.reset(m_coverage.size()-1); Chris@551: m_coverage.resize(column + 1); Chris@551: } Chris@546: Chris@545: Column peak; Chris@929: for (int i = 0; i < int(m_resolution); ++i) { Chris@545: Column here = m_source->getColumn(column * m_resolution + i); Chris@545: if (i == 0) { Chris@545: peak = here; Chris@545: } else { Chris@929: for (int j = 0; j < (int)peak.size() && j < (int)here.size(); ++j) { Chris@545: if (here[j] > peak[j]) peak[j] = here[j]; Chris@545: } Chris@545: } Chris@545: } Chris@546: Chris@545: m_cache->setColumn(column, peak); Chris@545: m_coverage.set(column); Chris@545: } Chris@545: Chris@545: