changeset 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 cff476cfce77
children 32c399d06374
files data/data.pro data/model/IntervalModel.h data/model/ModelDataTableModel.cpp data/model/NoteModel.cpp data/model/NoteModel.h
diffstat 5 files changed, 203 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/data/data.pro	Thu Jul 10 12:50:56 2008 +0000
+++ b/data/data.pro	Thu Aug 07 15:59:20 2008 +0000
@@ -50,6 +50,7 @@
            model/EditableDenseThreeDimensionalModel.h \
            model/FFTModel.h \
            model/ImageModel.h \
+           model/IntervalModel.h \
            model/Labeller.h \
            model/Model.h \
            model/ModelDataTableModel.h \
@@ -100,7 +101,6 @@
            model/FFTModel.cpp \
            model/Model.cpp \
            model/ModelDataTableModel.cpp \
-           model/NoteModel.cpp \
            model/PowerOfSqrtTwoZoomConstraint.cpp \
            model/PowerOfTwoZoomConstraint.cpp \
            model/RangeSummarisableTimeValueModel.cpp \
--- /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
--- a/data/model/ModelDataTableModel.cpp	Thu Jul 10 12:50:56 2008 +0000
+++ b/data/model/ModelDataTableModel.cpp	Thu Aug 07 15:59:20 2008 +0000
@@ -160,8 +160,8 @@
 void
 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
 {
-    std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
-              << ")" << std::endl;
+//    std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
+//              << ")" << std::endl;
     int prevCurrent = getCurrentRow();
     if (m_sortColumn != column) {
         clearSort();
@@ -170,7 +170,7 @@
     m_sortOrdering = sortOrder;
     int current = getCurrentRow();
     if (current != prevCurrent) {
-         std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
+//         std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
          emit currentChanged(createIndex(current, 0, 0));
     }
     emit layoutChanged();
--- a/data/model/NoteModel.cpp	Thu Jul 10 12:50:56 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/* -*- 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 Chris Cannam.
-    
-    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.
-*/
-
-#include "NoteModel.h"
-
-NoteModel::PointList
-NoteModel::getPoints(long start, long end) const
-{
-    if (start > end) return PointList();
-    QMutexLocker locker(&m_mutex);
-
-    Note endPoint(end);
-    
-    PointListIterator endItr = m_points.upper_bound(endPoint);
-
-    if (endItr != m_points.end()) ++endItr;
-    if (endItr != m_points.end()) ++endItr;
-
-    PointList rv;
-
-    for (PointListIterator i = endItr; 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;
-}
-
-NoteModel::PointList
-NoteModel::getPoints(long frame) const
-{
-    QMutexLocker locker(&m_mutex);
-
-    if (m_resolution == 0) return PointList();
-
-    long start = (frame / m_resolution) * m_resolution;
-    long end = start + m_resolution;
-
-    Note endPoint(end);
-    
-    PointListIterator endItr = m_points.upper_bound(endPoint);
-
-    PointList rv;
-
-    for (PointListIterator i = endItr; 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;
-}
--- a/data/model/NoteModel.h	Thu Jul 10 12:50:56 2008 +0000
+++ b/data/model/NoteModel.h	Thu Aug 07 15:59:20 2008 +0000
@@ -16,7 +16,7 @@
 #ifndef _NOTE_MODEL_H_
 #define _NOTE_MODEL_H_
 
-#include "SparseValueModel.h"
+#include "IntervalModel.h"
 #include "base/RealTime.h"
 #include "base/PlayParameterRepository.h"
 
@@ -86,15 +86,14 @@
 };
 
 
-class NoteModel : public SparseValueModel<Note>
+class NoteModel : public IntervalModel<Note>
 {
     Q_OBJECT
     
 public:
     NoteModel(size_t sampleRate, size_t resolution,
 	      bool notifyOnAdd = true) :
-	SparseValueModel<Note>(sampleRate, resolution,
-			       notifyOnAdd),
+	IntervalModel<Note>(sampleRate, resolution, notifyOnAdd),
 	m_valueQuantization(0)
     {
 	PlayParameterRepository::getInstance()->addPlayable(this);
@@ -103,9 +102,9 @@
     NoteModel(size_t sampleRate, size_t resolution,
 	      float valueMinimum, float valueMaximum,
 	      bool notifyOnAdd = true) :
-	SparseValueModel<Note>(sampleRate, resolution,
-			       valueMinimum, valueMaximum,
-			       notifyOnAdd),
+	IntervalModel<Note>(sampleRate, resolution,
+                            valueMinimum, valueMaximum,
+                            notifyOnAdd),
 	m_valueQuantization(0)
     {
 	PlayParameterRepository::getInstance()->addPlayable(this);
@@ -119,21 +118,6 @@
     float getValueQuantization() const { return m_valueQuantization; }
     void setValueQuantization(float q) { m_valueQuantization = q; }
 
-    /**
-     * Notes 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 PointList getPoints(long start, long end) const;
-
-    /**
-     * Notes 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 PointList getPoints(long frame) const;
-
     QString getTypeName() const { return tr("Note"); }
 
     virtual bool canPlay() const { return true; }
@@ -155,7 +139,7 @@
         std::cerr << "NoteModel::toXml: extraAttributes = \"" 
                   << extraAttributes.toStdString() << std::endl;
 
-        SparseValueModel<Note>::toXml
+        IntervalModel<Note>::toXml
 	    (out,
              indent,
 	     QString("%1 valueQuantization=\"%2\"")
@@ -186,19 +170,14 @@
 
     virtual QVariant getData(int row, int column, int role) const
     {
-        if (column < 2) {
-            return SparseValueModel<Note>::getData
-                (row, column, role);
+        if (column < 4) {
+            return IntervalModel<Note>::getData(row, column, role);
         }
 
         PointListIterator i = getPointListIteratorForRow(row);
         if (i == m_points.end()) return QVariant();
 
         switch (column) {
-        case 2:
-            if (role == Qt::EditRole || role == SortRole) return i->value;
-            else return QString("%1 %2").arg(i->value).arg(getScaleUnits());
-        case 3: return int(i->duration);
         case 4: return i->level;
         case 5: return i->label;
         default: return QVariant();
@@ -207,8 +186,8 @@
 
     virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role)
     {
-        if (column < 2) {
-            return SparseValueModel<Note>::getSetDataCommand
+        if (column < 4) {
+            return IntervalModel<Note>::getSetDataCommand
                 (row, column, value, role);
         }
 
@@ -221,9 +200,6 @@
         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;
         case 4: point.level = value.toDouble(); break;
         case 5: point.label = value.toString(); break;
         }
@@ -232,11 +208,6 @@
         return command->finish();
     }
 
-    virtual bool isColumnTimeValue(int column) const
-    {
-        return (column < 2); 
-    }
-
     virtual SortType getSortType(int column) const
     {
         if (column == 5) return SortAlphabetical;