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