Chris@152
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@152
|
2
|
Chris@152
|
3 /*
|
Chris@152
|
4 Sonic Visualiser
|
Chris@152
|
5 An audio file viewer and annotation editor.
|
Chris@152
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@152
|
7 This file copyright 2006 Chris Cannam.
|
Chris@152
|
8
|
Chris@152
|
9 This program is free software; you can redistribute it and/or
|
Chris@152
|
10 modify it under the terms of the GNU General Public License as
|
Chris@152
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@152
|
12 License, or (at your option) any later version. See the file
|
Chris@152
|
13 COPYING included with this distribution for more information.
|
Chris@152
|
14 */
|
Chris@152
|
15
|
Chris@152
|
16 #include "EditableDenseThreeDimensionalModel.h"
|
Chris@152
|
17
|
Chris@152
|
18 #include <QTextStream>
|
Chris@152
|
19
|
Chris@152
|
20 EditableDenseThreeDimensionalModel::EditableDenseThreeDimensionalModel(size_t sampleRate,
|
Chris@152
|
21 size_t resolution,
|
Chris@152
|
22 size_t yBinCount,
|
Chris@152
|
23 bool notifyOnAdd) :
|
Chris@152
|
24 m_sampleRate(sampleRate),
|
Chris@152
|
25 m_resolution(resolution),
|
Chris@152
|
26 m_yBinCount(yBinCount),
|
Chris@152
|
27 m_minimum(0.0),
|
Chris@152
|
28 m_maximum(0.0),
|
Chris@152
|
29 m_notifyOnAdd(notifyOnAdd),
|
Chris@152
|
30 m_sinceLastNotifyMin(-1),
|
Chris@152
|
31 m_sinceLastNotifyMax(-1),
|
Chris@152
|
32 m_completion(100)
|
Chris@152
|
33 {
|
Chris@152
|
34 }
|
Chris@152
|
35
|
Chris@152
|
36 bool
|
Chris@152
|
37 EditableDenseThreeDimensionalModel::isOK() const
|
Chris@152
|
38 {
|
Chris@152
|
39 return true;
|
Chris@152
|
40 }
|
Chris@152
|
41
|
Chris@152
|
42 size_t
|
Chris@152
|
43 EditableDenseThreeDimensionalModel::getSampleRate() const
|
Chris@152
|
44 {
|
Chris@152
|
45 return m_sampleRate;
|
Chris@152
|
46 }
|
Chris@152
|
47
|
Chris@152
|
48 size_t
|
Chris@152
|
49 EditableDenseThreeDimensionalModel::getStartFrame() const
|
Chris@152
|
50 {
|
Chris@152
|
51 return 0;
|
Chris@152
|
52 }
|
Chris@152
|
53
|
Chris@152
|
54 size_t
|
Chris@152
|
55 EditableDenseThreeDimensionalModel::getEndFrame() const
|
Chris@152
|
56 {
|
Chris@152
|
57 return m_resolution * m_data.size() + (m_resolution - 1);
|
Chris@152
|
58 }
|
Chris@152
|
59
|
Chris@152
|
60 Model *
|
Chris@152
|
61 EditableDenseThreeDimensionalModel::clone() const
|
Chris@152
|
62 {
|
Chris@152
|
63 EditableDenseThreeDimensionalModel *model =
|
Chris@152
|
64 new EditableDenseThreeDimensionalModel
|
Chris@152
|
65 (m_sampleRate, m_resolution, m_yBinCount);
|
Chris@152
|
66
|
Chris@152
|
67 model->m_minimum = m_minimum;
|
Chris@152
|
68 model->m_maximum = m_maximum;
|
Chris@152
|
69
|
Chris@152
|
70 for (size_t i = 0; i < m_data.size(); ++i) {
|
Chris@152
|
71 model->setBinValues(i * m_resolution, m_data[i]);
|
Chris@152
|
72 }
|
Chris@152
|
73
|
Chris@152
|
74 return model;
|
Chris@152
|
75 }
|
Chris@152
|
76
|
Chris@152
|
77 size_t
|
Chris@152
|
78 EditableDenseThreeDimensionalModel::getResolution() const
|
Chris@152
|
79 {
|
Chris@152
|
80 return m_resolution;
|
Chris@152
|
81 }
|
Chris@152
|
82
|
Chris@152
|
83 void
|
Chris@152
|
84 EditableDenseThreeDimensionalModel::setResolution(size_t sz)
|
Chris@152
|
85 {
|
Chris@152
|
86 m_resolution = sz;
|
Chris@152
|
87 }
|
Chris@152
|
88
|
Chris@152
|
89 size_t
|
Chris@152
|
90 EditableDenseThreeDimensionalModel::getYBinCount() const
|
Chris@152
|
91 {
|
Chris@152
|
92 return m_yBinCount;
|
Chris@152
|
93 }
|
Chris@152
|
94
|
Chris@152
|
95 void
|
Chris@152
|
96 EditableDenseThreeDimensionalModel::setYBinCount(size_t sz)
|
Chris@152
|
97 {
|
Chris@152
|
98 m_yBinCount = sz;
|
Chris@152
|
99 }
|
Chris@152
|
100
|
Chris@152
|
101 float
|
Chris@152
|
102 EditableDenseThreeDimensionalModel::getMinimumLevel() const
|
Chris@152
|
103 {
|
Chris@152
|
104 return m_minimum;
|
Chris@152
|
105 }
|
Chris@152
|
106
|
Chris@152
|
107 void
|
Chris@152
|
108 EditableDenseThreeDimensionalModel::setMinimumLevel(float level)
|
Chris@152
|
109 {
|
Chris@152
|
110 m_minimum = level;
|
Chris@152
|
111 }
|
Chris@152
|
112
|
Chris@152
|
113 float
|
Chris@152
|
114 EditableDenseThreeDimensionalModel::getMaximumLevel() const
|
Chris@152
|
115 {
|
Chris@152
|
116 return m_maximum;
|
Chris@152
|
117 }
|
Chris@152
|
118
|
Chris@152
|
119 void
|
Chris@152
|
120 EditableDenseThreeDimensionalModel::setMaximumLevel(float level)
|
Chris@152
|
121 {
|
Chris@152
|
122 m_maximum = level;
|
Chris@152
|
123 }
|
Chris@152
|
124
|
Chris@152
|
125 void
|
Chris@152
|
126 EditableDenseThreeDimensionalModel::getBinValues(long windowStart,
|
Chris@152
|
127 BinValueSet &result) const
|
Chris@152
|
128 {
|
Chris@152
|
129 QMutexLocker locker(&m_mutex);
|
Chris@152
|
130
|
Chris@152
|
131 long index = windowStart / m_resolution;
|
Chris@152
|
132
|
Chris@152
|
133 if (index >= 0 && index < long(m_data.size())) {
|
Chris@152
|
134 result = m_data[index];
|
Chris@152
|
135 } else {
|
Chris@152
|
136 result.clear();
|
Chris@152
|
137 }
|
Chris@152
|
138
|
Chris@152
|
139 while (result.size() < m_yBinCount) result.push_back(m_minimum);
|
Chris@152
|
140 }
|
Chris@152
|
141
|
Chris@152
|
142 float
|
Chris@152
|
143 EditableDenseThreeDimensionalModel::getBinValue(long windowStart,
|
Chris@152
|
144 size_t n) const
|
Chris@152
|
145 {
|
Chris@152
|
146 QMutexLocker locker(&m_mutex);
|
Chris@152
|
147
|
Chris@152
|
148 long index = windowStart / m_resolution;
|
Chris@152
|
149
|
Chris@152
|
150 if (index >= 0 && index < long(m_data.size())) {
|
Chris@152
|
151 const BinValueSet &s = m_data[index];
|
Chris@152
|
152 if (n < s.size()) return s[n];
|
Chris@152
|
153 }
|
Chris@152
|
154
|
Chris@152
|
155 return m_minimum;
|
Chris@152
|
156 }
|
Chris@152
|
157
|
Chris@152
|
158 void
|
Chris@152
|
159 EditableDenseThreeDimensionalModel::setBinValues(long windowStart,
|
Chris@152
|
160 const BinValueSet &values)
|
Chris@152
|
161 {
|
Chris@152
|
162 QMutexLocker locker(&m_mutex);
|
Chris@152
|
163
|
Chris@152
|
164 long index = windowStart / m_resolution;
|
Chris@152
|
165
|
Chris@152
|
166 while (index >= long(m_data.size())) {
|
Chris@152
|
167 m_data.push_back(BinValueSet());
|
Chris@152
|
168 }
|
Chris@152
|
169
|
Chris@152
|
170 bool newExtents = (m_data.empty() && (m_minimum == m_maximum));
|
Chris@152
|
171 bool allChange = false;
|
Chris@152
|
172
|
Chris@152
|
173 for (size_t i = 0; i < values.size(); ++i) {
|
Chris@152
|
174 if (newExtents || values[i] < m_minimum) {
|
Chris@152
|
175 m_minimum = values[i];
|
Chris@152
|
176 allChange = true;
|
Chris@152
|
177 }
|
Chris@152
|
178 if (newExtents || values[i] > m_maximum) {
|
Chris@152
|
179 m_maximum = values[i];
|
Chris@152
|
180 allChange = true;
|
Chris@152
|
181 }
|
Chris@152
|
182 }
|
Chris@152
|
183
|
Chris@152
|
184 m_data[index] = values;
|
Chris@152
|
185
|
Chris@152
|
186 if (m_notifyOnAdd) {
|
Chris@152
|
187 if (allChange) {
|
Chris@152
|
188 emit modelChanged();
|
Chris@152
|
189 } else {
|
Chris@152
|
190 emit modelChanged(windowStart, windowStart + m_resolution);
|
Chris@152
|
191 }
|
Chris@152
|
192 } else {
|
Chris@152
|
193 if (allChange) {
|
Chris@152
|
194 m_sinceLastNotifyMin = -1;
|
Chris@152
|
195 m_sinceLastNotifyMax = -1;
|
Chris@152
|
196 emit modelChanged();
|
Chris@152
|
197 } else {
|
Chris@152
|
198 if (m_sinceLastNotifyMin == -1 ||
|
Chris@152
|
199 windowStart < m_sinceLastNotifyMin) {
|
Chris@152
|
200 m_sinceLastNotifyMin = windowStart;
|
Chris@152
|
201 }
|
Chris@152
|
202 if (m_sinceLastNotifyMax == -1 ||
|
Chris@152
|
203 windowStart > m_sinceLastNotifyMax) {
|
Chris@152
|
204 m_sinceLastNotifyMax = windowStart;
|
Chris@152
|
205 }
|
Chris@152
|
206 }
|
Chris@152
|
207 }
|
Chris@152
|
208 }
|
Chris@152
|
209
|
Chris@152
|
210 QString
|
Chris@152
|
211 EditableDenseThreeDimensionalModel::getBinName(size_t n) const
|
Chris@152
|
212 {
|
Chris@152
|
213 if (m_binNames.size() > n) return m_binNames[n];
|
Chris@152
|
214 else return "";
|
Chris@152
|
215 }
|
Chris@152
|
216
|
Chris@152
|
217 void
|
Chris@152
|
218 EditableDenseThreeDimensionalModel::setBinName(size_t n, QString name)
|
Chris@152
|
219 {
|
Chris@152
|
220 while (m_binNames.size() <= n) m_binNames.push_back("");
|
Chris@152
|
221 m_binNames[n] = name;
|
Chris@152
|
222 emit modelChanged();
|
Chris@152
|
223 }
|
Chris@152
|
224
|
Chris@152
|
225 void
|
Chris@152
|
226 EditableDenseThreeDimensionalModel::setBinNames(std::vector<QString> names)
|
Chris@152
|
227 {
|
Chris@152
|
228 m_binNames = names;
|
Chris@152
|
229 emit modelChanged();
|
Chris@152
|
230 }
|
Chris@152
|
231
|
Chris@152
|
232 void
|
Chris@152
|
233 EditableDenseThreeDimensionalModel::setCompletion(int completion)
|
Chris@152
|
234 {
|
Chris@152
|
235 if (m_completion != completion) {
|
Chris@152
|
236 m_completion = completion;
|
Chris@152
|
237
|
Chris@152
|
238 if (completion == 100) {
|
Chris@152
|
239
|
Chris@152
|
240 m_notifyOnAdd = true; // henceforth
|
Chris@152
|
241 emit modelChanged();
|
Chris@152
|
242
|
Chris@152
|
243 } else if (!m_notifyOnAdd) {
|
Chris@152
|
244
|
Chris@152
|
245 if (m_sinceLastNotifyMin >= 0 &&
|
Chris@152
|
246 m_sinceLastNotifyMax >= 0) {
|
Chris@152
|
247 emit modelChanged(m_sinceLastNotifyMin,
|
Chris@152
|
248 m_sinceLastNotifyMax + m_resolution);
|
Chris@152
|
249 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
|
Chris@152
|
250 } else {
|
Chris@152
|
251 emit completionChanged();
|
Chris@152
|
252 }
|
Chris@152
|
253 } else {
|
Chris@152
|
254 emit completionChanged();
|
Chris@152
|
255 }
|
Chris@152
|
256 }
|
Chris@152
|
257 }
|
Chris@152
|
258
|
Chris@152
|
259 void
|
Chris@152
|
260 EditableDenseThreeDimensionalModel::toXml(QTextStream &out,
|
Chris@152
|
261 QString indent,
|
Chris@152
|
262 QString extraAttributes) const
|
Chris@152
|
263 {
|
Chris@152
|
264 // For historical reasons we read and write "resolution" as "windowSize"
|
Chris@152
|
265
|
Chris@152
|
266 out << Model::toXmlString
|
Chris@152
|
267 (indent, QString("type=\"dense\" dimensions=\"3\" windowSize=\"%1\" yBinCount=\"%2\" minimum=\"%3\" maximum=\"%4\" dataset=\"%5\" %6")
|
Chris@152
|
268 .arg(m_resolution)
|
Chris@152
|
269 .arg(m_yBinCount)
|
Chris@152
|
270 .arg(m_minimum)
|
Chris@152
|
271 .arg(m_maximum)
|
Chris@152
|
272 .arg(getObjectExportId(&m_data))
|
Chris@152
|
273 .arg(extraAttributes));
|
Chris@152
|
274
|
Chris@152
|
275 out << indent;
|
Chris@152
|
276 out << QString("<dataset id=\"%1\" dimensions=\"3\" separator=\" \">\n")
|
Chris@152
|
277 .arg(getObjectExportId(&m_data));
|
Chris@152
|
278
|
Chris@152
|
279 for (size_t i = 0; i < m_binNames.size(); ++i) {
|
Chris@152
|
280 if (m_binNames[i] != "") {
|
Chris@152
|
281 out << indent + " ";
|
Chris@152
|
282 out << QString("<bin number=\"%1\" name=\"%2\"/>\n")
|
Chris@152
|
283 .arg(i).arg(m_binNames[i]);
|
Chris@152
|
284 }
|
Chris@152
|
285 }
|
Chris@152
|
286
|
Chris@152
|
287 for (size_t i = 0; i < m_data.size(); ++i) {
|
Chris@152
|
288 out << indent + " ";
|
Chris@152
|
289 out << QString("<row n=\"%1\">").arg(i);
|
Chris@152
|
290 for (size_t j = 0; j < m_data[i].size(); ++j) {
|
Chris@152
|
291 if (j > 0) out << " ";
|
Chris@152
|
292 out << m_data[i][j];
|
Chris@152
|
293 }
|
Chris@152
|
294 out << QString("</row>\n");
|
Chris@152
|
295 }
|
Chris@152
|
296
|
Chris@152
|
297 out << indent + "</dataset>\n";
|
Chris@152
|
298 }
|
Chris@152
|
299
|
Chris@152
|
300 QString
|
Chris@152
|
301 EditableDenseThreeDimensionalModel::toXmlString(QString indent,
|
Chris@152
|
302 QString extraAttributes) const
|
Chris@152
|
303 {
|
Chris@152
|
304 QString s;
|
Chris@152
|
305
|
Chris@152
|
306 {
|
Chris@152
|
307 QTextStream out(&s);
|
Chris@152
|
308 toXml(out, indent, extraAttributes);
|
Chris@152
|
309 }
|
Chris@152
|
310
|
Chris@152
|
311 return s;
|
Chris@152
|
312 }
|
Chris@152
|
313
|
Chris@152
|
314 #ifdef INCLUDE_MOCFILES
|
Chris@152
|
315 #include "EditableDenseThreeDimensionalModel.moc.cpp"
|
Chris@152
|
316 #endif
|
Chris@152
|
317
|