comparison 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
comparison
equal deleted inserted replaced
436:cff476cfce77 437:7226ebac8bd3
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2006-2008 Chris Cannam and QMUL.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #ifndef _INTERVAL_MODEL_H_
17 #define _INTERVAL_MODEL_H_
18
19 #include "SparseValueModel.h"
20 #include "base/RealTime.h"
21
22 /**
23 * Model containing sparse data (points with some properties) of which
24 * the properties include a duration and an arbitrary float value.
25 * The other properties depend on the point type.
26 */
27
28 template <typename PointType>
29 class IntervalModel : public SparseValueModel<PointType>
30 {
31 public:
32 IntervalModel(size_t sampleRate, size_t resolution,
33 bool notifyOnAdd = true) :
34 SparseValueModel<PointType>(sampleRate, resolution, notifyOnAdd)
35 { }
36
37 IntervalModel(size_t sampleRate, size_t resolution,
38 float valueMinimum, float valueMaximum,
39 bool notifyOnAdd = true) :
40 SparseValueModel<PointType>(sampleRate, resolution,
41 valueMinimum, valueMaximum,
42 notifyOnAdd)
43 { }
44
45 /**
46 * PointTypes have a duration, so this returns all points that span any
47 * of the given range (as well as the usual additional few before
48 * and after). Consequently this can be very slow (optimised data
49 * structures still to be done!).
50 */
51 virtual typename SparseValueModel<PointType>::PointList getPoints(long start, long end) const;
52
53 /**
54 * PointTypes have a duration, so this returns all points that span the
55 * given frame. Consequently this can be very slow (optimised
56 * data structures still to be done!).
57 */
58 virtual typename SparseValueModel<PointType>::PointList getPoints(long frame) const;
59
60 /**
61 * TabularModel methods.
62 */
63
64 virtual QVariant getData(int row, int column, int role) const
65 {
66 if (column < 2) {
67 return SparseValueModel<PointType>::getData
68 (row, column, role);
69 }
70
71 typename SparseModel<PointType>::PointList::const_iterator i
72 = SparseModel<PointType>::getPointListIteratorForRow(row);
73 if (i == SparseModel<PointType>::m_points.end()) return QVariant();
74
75 switch (column) {
76 case 2:
77 if (role == Qt::EditRole || role == TabularModel::SortRole) return i->value;
78 else return QString("%1 %2").arg(i->value).arg
79 (IntervalModel<PointType>::getScaleUnits());
80 case 3: return int(i->duration); //!!! could be better presented
81 default: return QVariant();
82 }
83 }
84
85 virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role)
86 {
87 if (column < 2) {
88 return SparseValueModel<PointType>::getSetDataCommand
89 (row, column, value, role);
90 }
91
92 if (role != Qt::EditRole) return false;
93 // gah. This is such garbage. Thank you, C++! I love you too
94 typename SparseModel<PointType>::PointList::const_iterator i
95 = SparseModel<PointType>::getPointListIteratorForRow(row);
96 if (i == SparseModel<PointType>::m_points.end()) return false;
97 typename IntervalModel<PointType>::EditCommand *command
98 = new typename IntervalModel<PointType>::EditCommand
99 (this, IntervalModel<PointType>::tr("Edit Data"));
100
101 PointType point(*i);
102 command->deletePoint(point);
103
104 switch (column) {
105 case 0: case 1: point.frame = value.toInt(); break;
106 case 2: point.value = value.toDouble(); break;
107 case 3: point.duration = value.toInt(); break;
108 }
109
110 command->addPoint(point);
111 return command->finish();
112 }
113
114 virtual bool isColumnTimeValue(int column) const
115 {
116 return (column < 2 || column == 3);
117 }
118 };
119
120 template <typename PointType>
121 typename SparseValueModel<PointType>::PointList
122 IntervalModel<PointType>::getPoints(long start, long end) const
123 {
124 typedef IntervalModel<PointType> I;
125
126 if (start > end) return typename I::PointList();
127
128 QMutex &mutex(I::m_mutex);
129 QMutexLocker locker(&mutex);
130
131 PointType endPoint(end);
132
133 typename I::PointListIterator endItr = I::m_points.upper_bound(endPoint);
134
135 if (endItr != I::m_points.end()) ++endItr;
136 if (endItr != I::m_points.end()) ++endItr;
137
138 typename I::PointList rv;
139
140 for (typename I::PointListIterator i = endItr; i != I::m_points.begin(); ) {
141 --i;
142 if (i->frame < start) {
143 if (i->frame + long(i->duration) >= start) {
144 rv.insert(*i);
145 }
146 } else if (i->frame <= end) {
147 rv.insert(*i);
148 }
149 }
150
151 return rv;
152 }
153
154 template <typename PointType>
155 typename SparseValueModel<PointType>::PointList
156 IntervalModel<PointType>::getPoints(long frame) const
157 {
158 typedef IntervalModel<PointType> I;
159
160 QMutex &mutex(I::m_mutex);
161 QMutexLocker locker(&mutex);
162
163 if (I::m_resolution == 0) return typename I::PointList();
164
165 long start = (frame / I::m_resolution) * I::m_resolution;
166 long end = start + I::m_resolution;
167
168 PointType endPoint(end);
169
170 typename I::PointListIterator endItr = I::m_points.upper_bound(endPoint);
171
172 typename I::PointList rv;
173
174 for (typename I::PointListIterator i = endItr; i != I::m_points.begin(); ) {
175 --i;
176 if (i->frame < start) {
177 if (i->frame + long(i->duration) >= start) {
178 rv.insert(*i);
179 }
180 } else if (i->frame <= end) {
181 rv.insert(*i);
182 }
183 }
184
185 return rv;
186 }
187
188 #endif