diff data/model/IntervalModel.h @ 437:7226ebac8bd3

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