Chris@437: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@437: Chris@437: /* Chris@437: Sonic Visualiser Chris@437: An audio file viewer and annotation editor. Chris@437: Centre for Digital Music, Queen Mary, University of London. Chris@437: This file copyright 2006-2008 Chris Cannam and QMUL. Chris@437: Chris@437: This program is free software; you can redistribute it and/or Chris@437: modify it under the terms of the GNU General Public License as Chris@437: published by the Free Software Foundation; either version 2 of the Chris@437: License, or (at your option) any later version. See the file Chris@437: COPYING included with this distribution for more information. Chris@437: */ Chris@437: Chris@437: #ifndef _INTERVAL_MODEL_H_ Chris@437: #define _INTERVAL_MODEL_H_ Chris@437: Chris@437: #include "SparseValueModel.h" Chris@437: #include "base/RealTime.h" Chris@437: Chris@437: /** Chris@437: * Model containing sparse data (points with some properties) of which Chris@437: * the properties include a duration and an arbitrary float value. Chris@437: * The other properties depend on the point type. Chris@437: */ Chris@437: Chris@437: template Chris@437: class IntervalModel : public SparseValueModel Chris@437: { Chris@437: public: Chris@437: IntervalModel(size_t sampleRate, size_t resolution, Chris@437: bool notifyOnAdd = true) : Chris@437: SparseValueModel(sampleRate, resolution, notifyOnAdd) Chris@437: { } Chris@437: Chris@437: IntervalModel(size_t sampleRate, size_t resolution, Chris@437: float valueMinimum, float valueMaximum, Chris@437: bool notifyOnAdd = true) : Chris@437: SparseValueModel(sampleRate, resolution, Chris@437: valueMinimum, valueMaximum, Chris@437: notifyOnAdd) Chris@437: { } Chris@437: Chris@437: /** Chris@437: * PointTypes have a duration, so this returns all points that span any Chris@437: * of the given range (as well as the usual additional few before Chris@437: * and after). Consequently this can be very slow (optimised data Chris@437: * structures still to be done!). Chris@437: */ Chris@437: virtual typename SparseValueModel::PointList getPoints(long start, long end) const; Chris@437: Chris@437: /** Chris@437: * PointTypes have a duration, so this returns all points that span the Chris@437: * given frame. Consequently this can be very slow (optimised Chris@437: * data structures still to be done!). Chris@437: */ Chris@437: virtual typename SparseValueModel::PointList getPoints(long frame) const; Chris@437: Chris@459: virtual const typename SparseModel::PointList &getPoints() const { Chris@459: return SparseModel::getPoints(); Chris@459: } Chris@459: Chris@437: /** Chris@437: * TabularModel methods. Chris@437: */ Chris@437: Chris@437: virtual QVariant getData(int row, int column, int role) const Chris@437: { Chris@437: if (column < 2) { Chris@437: return SparseValueModel::getData Chris@437: (row, column, role); Chris@437: } Chris@437: Chris@437: typename SparseModel::PointList::const_iterator i Chris@437: = SparseModel::getPointListIteratorForRow(row); Chris@437: if (i == SparseModel::m_points.end()) return QVariant(); Chris@437: Chris@437: switch (column) { Chris@437: case 2: Chris@437: if (role == Qt::EditRole || role == TabularModel::SortRole) return i->value; Chris@437: else return QString("%1 %2").arg(i->value).arg Chris@437: (IntervalModel::getScaleUnits()); Chris@437: case 3: return int(i->duration); //!!! could be better presented Chris@437: default: return QVariant(); Chris@437: } Chris@437: } Chris@437: Chris@437: virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role) Chris@437: { Chris@438: typedef IntervalModel I; Chris@438: Chris@437: if (column < 2) { Chris@437: return SparseValueModel::getSetDataCommand Chris@437: (row, column, value, role); Chris@437: } Chris@437: Chris@437: if (role != Qt::EditRole) return false; Chris@438: typename I::PointList::const_iterator i Chris@438: = I::getPointListIteratorForRow(row); Chris@438: if (i == I::m_points.end()) return false; Chris@438: typename I::EditCommand *command = new typename I::EditCommand Chris@438: (this, I::tr("Edit Data")); Chris@437: Chris@437: PointType point(*i); Chris@437: command->deletePoint(point); Chris@437: Chris@437: switch (column) { Chris@437: case 0: case 1: point.frame = value.toInt(); break; Chris@437: case 2: point.value = value.toDouble(); break; Chris@437: case 3: point.duration = value.toInt(); break; Chris@437: } Chris@437: Chris@437: command->addPoint(point); Chris@437: return command->finish(); Chris@437: } Chris@437: Chris@437: virtual bool isColumnTimeValue(int column) const Chris@437: { Chris@437: return (column < 2 || column == 3); Chris@437: } Chris@437: }; Chris@437: Chris@437: template Chris@437: typename SparseValueModel::PointList Chris@437: IntervalModel::getPoints(long start, long end) const Chris@437: { Chris@437: typedef IntervalModel I; Chris@437: Chris@437: if (start > end) return typename I::PointList(); Chris@437: Chris@437: QMutex &mutex(I::m_mutex); Chris@437: QMutexLocker locker(&mutex); Chris@437: Chris@437: PointType endPoint(end); Chris@437: Chris@437: typename I::PointListIterator endItr = I::m_points.upper_bound(endPoint); Chris@437: Chris@437: if (endItr != I::m_points.end()) ++endItr; Chris@437: if (endItr != I::m_points.end()) ++endItr; Chris@437: Chris@437: typename I::PointList rv; Chris@437: Chris@437: for (typename I::PointListIterator i = endItr; i != I::m_points.begin(); ) { Chris@437: --i; Chris@437: if (i->frame < start) { Chris@437: if (i->frame + long(i->duration) >= start) { Chris@437: rv.insert(*i); Chris@437: } Chris@437: } else if (i->frame <= end) { Chris@437: rv.insert(*i); Chris@437: } Chris@437: } Chris@437: Chris@437: return rv; Chris@437: } Chris@437: Chris@437: template Chris@437: typename SparseValueModel::PointList Chris@437: IntervalModel::getPoints(long frame) const Chris@437: { Chris@437: typedef IntervalModel I; Chris@437: Chris@437: QMutex &mutex(I::m_mutex); Chris@437: QMutexLocker locker(&mutex); Chris@437: Chris@437: if (I::m_resolution == 0) return typename I::PointList(); Chris@437: Chris@437: long start = (frame / I::m_resolution) * I::m_resolution; Chris@437: long end = start + I::m_resolution; Chris@437: Chris@437: PointType endPoint(end); Chris@437: Chris@437: typename I::PointListIterator endItr = I::m_points.upper_bound(endPoint); Chris@437: Chris@437: typename I::PointList rv; Chris@437: Chris@437: for (typename I::PointListIterator i = endItr; i != I::m_points.begin(); ) { Chris@437: --i; Chris@437: if (i->frame < start) { Chris@437: if (i->frame + long(i->duration) >= start) { Chris@437: rv.insert(*i); Chris@437: } Chris@437: } else if (i->frame <= end) { Chris@437: rv.insert(*i); Chris@437: } Chris@437: } Chris@437: Chris@437: return rv; Chris@437: } Chris@437: Chris@437: #endif