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@545: 					     size_t 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@545: Dense3DModelPeakCache::isColumnAvailable(size_t 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@545: Dense3DModelPeakCache::getColumn(size_t 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@545: Dense3DModelPeakCache::getValueAt(size_t column, size_t 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@545: Dense3DModelPeakCache::haveColumn(size_t column) const
Chris@545: {
Chris@546:     return column < m_coverage.size() && m_coverage.get(column);
Chris@545: }
Chris@545: 
Chris@545: void
Chris@545: Dense3DModelPeakCache::fillColumn(size_t column) const
Chris@545: {
Chris@551:     Profiler profiler("Dense3DModelPeakCache::fillColumn");
Chris@551: 
Chris@551:     if (column >= 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@545:     for (int i = 0; i < 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@545:             for (int j = 0; j < peak.size() && j < 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: