Chris@1611
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1611
|
2
|
Chris@1611
|
3 /*
|
Chris@1611
|
4 Sonic Visualiser
|
Chris@1611
|
5 An audio file viewer and annotation editor.
|
Chris@1611
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@1611
|
7 This file copyright 2006 Chris Cannam.
|
Chris@1611
|
8
|
Chris@1611
|
9 This program is free software; you can redistribute it and/or
|
Chris@1611
|
10 modify it under the terms of the GNU General Public License as
|
Chris@1611
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@1611
|
12 License, or (at your option) any later version. See the file
|
Chris@1611
|
13 COPYING included with this distribution for more information.
|
Chris@1611
|
14 */
|
Chris@1611
|
15
|
Chris@1615
|
16 #ifndef SV_EVENT_H
|
Chris@1615
|
17 #define SV_EVENT_H
|
Chris@1615
|
18
|
Chris@1615
|
19 #include "BaseTypes.h"
|
Chris@1615
|
20 #include "NoteData.h"
|
Chris@1615
|
21 #include "XmlExportable.h"
|
Chris@1629
|
22 #include "DataExportOptions.h"
|
Chris@1615
|
23
|
Chris@1615
|
24 #include <vector>
|
Chris@1615
|
25 #include <stdexcept>
|
Chris@1611
|
26
|
Chris@1611
|
27 #include <QString>
|
Chris@1611
|
28
|
Chris@1800
|
29 #if (QT_VERSION < QT_VERSION_CHECK(5, 3, 0))
|
Chris@1803
|
30 #ifdef __GNUC__
|
Chris@1803
|
31 #pragma GCC diagnostic ignored "-Wunused-function"
|
Chris@1803
|
32 #endif
|
Chris@1803
|
33 static uint qHash(float key, uint seed = 0) {
|
Chris@1801
|
34 uint h = seed;
|
Chris@1801
|
35 const uchar *p = reinterpret_cast<const uchar *>(&key);
|
Chris@1801
|
36 for (size_t i = 0; i < sizeof(key); ++i) {
|
Chris@1801
|
37 h = 31 * h + p[i];
|
Chris@1801
|
38 }
|
Chris@1801
|
39 return h;
|
Chris@1800
|
40 }
|
Chris@1800
|
41 #endif
|
Chris@1800
|
42
|
Chris@1615
|
43 /**
|
Chris@1647
|
44 * An immutable(-ish) type used for point and event representation in
|
Chris@1647
|
45 * sparse models, as well as for interchange within the clipboard. An
|
Chris@1647
|
46 * event always has a frame and (possibly empty) label, and optionally
|
Chris@1647
|
47 * has numerical value, level, duration in frames, and a mapped
|
Chris@1647
|
48 * reference frame. Event has an operator< defining a total ordering,
|
Chris@1647
|
49 * by frame first and then by the other properties.
|
Chris@1615
|
50 *
|
Chris@1615
|
51 * Event is based on the Clipboard::Point type up to SV v3.2.1 and is
|
Chris@1615
|
52 * intended also to replace the custom point types previously found in
|
Chris@1615
|
53 * sparse models.
|
Chris@1615
|
54 */
|
Chris@1615
|
55 class Event
|
Chris@1611
|
56 {
|
Chris@1611
|
57 public:
|
Chris@1623
|
58 Event() :
|
Chris@1629
|
59 m_haveValue(false), m_haveLevel(false),
|
Chris@1629
|
60 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1623
|
61 m_value(0.f), m_level(0.f), m_frame(0),
|
Chris@1623
|
62 m_duration(0), m_referenceFrame(0), m_label() { }
|
Chris@1623
|
63
|
Chris@1615
|
64 Event(sv_frame_t frame) :
|
Chris@1629
|
65 m_haveValue(false), m_haveLevel(false),
|
Chris@1629
|
66 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1615
|
67 m_value(0.f), m_level(0.f), m_frame(frame),
|
Chris@1615
|
68 m_duration(0), m_referenceFrame(0), m_label() { }
|
Chris@1615
|
69
|
Chris@1615
|
70 Event(sv_frame_t frame, QString label) :
|
Chris@1629
|
71 m_haveValue(false), m_haveLevel(false),
|
Chris@1629
|
72 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1611
|
73 m_value(0.f), m_level(0.f), m_frame(frame),
|
Chris@1611
|
74 m_duration(0), m_referenceFrame(0), m_label(label) { }
|
Chris@1611
|
75
|
Chris@1615
|
76 Event(sv_frame_t frame, float value, QString label) :
|
Chris@1629
|
77 m_haveValue(true), m_haveLevel(false),
|
Chris@1629
|
78 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1611
|
79 m_value(value), m_level(0.f), m_frame(frame),
|
Chris@1611
|
80 m_duration(0), m_referenceFrame(0), m_label(label) { }
|
Chris@1611
|
81
|
Chris@1615
|
82 Event(sv_frame_t frame, float value, sv_frame_t duration, QString label) :
|
Chris@1629
|
83 m_haveValue(true), m_haveLevel(false),
|
Chris@1629
|
84 m_haveDuration(true), m_haveReferenceFrame(false),
|
Chris@1611
|
85 m_value(value), m_level(0.f), m_frame(frame),
|
Chris@1615
|
86 m_duration(duration), m_referenceFrame(0), m_label(label) {
|
Chris@1866
|
87 if (m_duration < 0) {
|
Chris@1866
|
88 m_frame += m_duration;
|
Chris@1866
|
89 m_duration = -m_duration;
|
Chris@1866
|
90 }
|
Chris@1615
|
91 }
|
Chris@1611
|
92
|
Chris@1615
|
93 Event(sv_frame_t frame, float value, sv_frame_t duration,
|
Chris@1612
|
94 float level, QString label) :
|
Chris@1629
|
95 m_haveValue(true), m_haveLevel(true),
|
Chris@1629
|
96 m_haveDuration(true), m_haveReferenceFrame(false),
|
Chris@1611
|
97 m_value(value), m_level(level), m_frame(frame),
|
Chris@1615
|
98 m_duration(duration), m_referenceFrame(0), m_label(label) {
|
Chris@1866
|
99 if (m_duration < 0) {
|
Chris@1866
|
100 m_frame += m_duration;
|
Chris@1866
|
101 m_duration = -m_duration;
|
Chris@1866
|
102 }
|
Chris@1615
|
103 }
|
Chris@1611
|
104
|
Chris@1615
|
105 Event(const Event &event) =default;
|
Chris@1647
|
106
|
Chris@1647
|
107 // We would ideally like Event to be immutable - but we have to
|
Chris@1647
|
108 // have these because otherwise we can't put Events in vectors
|
Chris@1647
|
109 // etc. Let's call it conceptually immutable
|
Chris@1615
|
110 Event &operator=(const Event &event) =default;
|
Chris@1615
|
111 Event &operator=(Event &&event) =default;
|
Chris@1611
|
112
|
Chris@1611
|
113 sv_frame_t getFrame() const { return m_frame; }
|
Chris@1611
|
114
|
Chris@1615
|
115 Event withFrame(sv_frame_t frame) const {
|
Chris@1615
|
116 Event p(*this);
|
Chris@1611
|
117 p.m_frame = frame;
|
Chris@1611
|
118 return p;
|
Chris@1611
|
119 }
|
Chris@1611
|
120
|
Chris@1615
|
121 bool hasValue() const { return m_haveValue; }
|
Chris@1634
|
122 float getValue() const { return m_haveValue ? m_value : 0.f; }
|
Chris@1611
|
123
|
Chris@1615
|
124 Event withValue(float value) const {
|
Chris@1615
|
125 Event p(*this);
|
Chris@1611
|
126 p.m_haveValue = true;
|
Chris@1611
|
127 p.m_value = value;
|
Chris@1611
|
128 return p;
|
Chris@1611
|
129 }
|
Chris@1615
|
130 Event withoutValue() const {
|
Chris@1615
|
131 Event p(*this);
|
Chris@1615
|
132 p.m_haveValue = false;
|
Chris@1615
|
133 p.m_value = 0.f;
|
Chris@1615
|
134 return p;
|
Chris@1615
|
135 }
|
Chris@1611
|
136
|
Chris@1629
|
137 bool hasDuration() const { return m_haveDuration; }
|
Chris@1634
|
138 sv_frame_t getDuration() const { return m_haveDuration ? m_duration : 0; }
|
Chris@1611
|
139
|
Chris@1615
|
140 Event withDuration(sv_frame_t duration) const {
|
Chris@1615
|
141 Event p(*this);
|
Chris@1611
|
142 p.m_duration = duration;
|
Chris@1629
|
143 p.m_haveDuration = true;
|
Chris@1866
|
144 if (p.m_duration < 0) {
|
Chris@1866
|
145 p.m_frame += p.m_duration;
|
Chris@1866
|
146 p.m_duration = -p.m_duration;
|
Chris@1866
|
147 }
|
Chris@1615
|
148 return p;
|
Chris@1615
|
149 }
|
Chris@1615
|
150 Event withoutDuration() const {
|
Chris@1615
|
151 Event p(*this);
|
Chris@1629
|
152 p.m_haveDuration = false;
|
Chris@1615
|
153 p.m_duration = 0;
|
Chris@1611
|
154 return p;
|
Chris@1611
|
155 }
|
Chris@1620
|
156
|
Chris@1620
|
157 bool hasLabel() const { return m_label != QString(); }
|
Chris@1611
|
158 QString getLabel() const { return m_label; }
|
Chris@1611
|
159
|
Chris@1615
|
160 Event withLabel(QString label) const {
|
Chris@1615
|
161 Event p(*this);
|
Chris@1611
|
162 p.m_label = label;
|
Chris@1611
|
163 return p;
|
Chris@1611
|
164 }
|
Chris@1663
|
165
|
Chris@1663
|
166 bool hasUri() const { return m_uri != QString(); }
|
Chris@1663
|
167 QString getURI() const { return m_uri; }
|
Chris@1663
|
168
|
Chris@1663
|
169 Event withURI(QString uri) const {
|
Chris@1663
|
170 Event p(*this);
|
Chris@1663
|
171 p.m_uri = uri;
|
Chris@1663
|
172 return p;
|
Chris@1663
|
173 }
|
Chris@1611
|
174
|
Chris@1615
|
175 bool hasLevel() const { return m_haveLevel; }
|
Chris@1634
|
176 float getLevel() const { return m_haveLevel ? m_level : 0.f; }
|
Chris@1615
|
177
|
Chris@1615
|
178 Event withLevel(float level) const {
|
Chris@1615
|
179 Event p(*this);
|
Chris@1611
|
180 p.m_haveLevel = true;
|
Chris@1611
|
181 p.m_level = level;
|
Chris@1611
|
182 return p;
|
Chris@1611
|
183 }
|
Chris@1615
|
184 Event withoutLevel() const {
|
Chris@1615
|
185 Event p(*this);
|
Chris@1615
|
186 p.m_haveLevel = false;
|
Chris@1615
|
187 p.m_level = 0.f;
|
Chris@1615
|
188 return p;
|
Chris@1615
|
189 }
|
Chris@1611
|
190
|
Chris@1615
|
191 bool hasReferenceFrame() const { return m_haveReferenceFrame; }
|
Chris@1634
|
192 sv_frame_t getReferenceFrame() const {
|
Chris@1634
|
193 return m_haveReferenceFrame ? m_referenceFrame : m_frame;
|
Chris@1634
|
194 }
|
Chris@1611
|
195
|
Chris@1615
|
196 bool referenceFrameDiffers() const { // from event frame
|
Chris@1611
|
197 return m_haveReferenceFrame && (m_referenceFrame != m_frame);
|
Chris@1611
|
198 }
|
Chris@1611
|
199
|
Chris@1615
|
200 Event withReferenceFrame(sv_frame_t frame) const {
|
Chris@1615
|
201 Event p(*this);
|
Chris@1611
|
202 p.m_haveReferenceFrame = true;
|
Chris@1611
|
203 p.m_referenceFrame = frame;
|
Chris@1611
|
204 return p;
|
Chris@1611
|
205 }
|
Chris@1615
|
206 Event withoutReferenceFrame() const {
|
Chris@1615
|
207 Event p(*this);
|
Chris@1615
|
208 p.m_haveReferenceFrame = false;
|
Chris@1615
|
209 p.m_referenceFrame = 0;
|
Chris@1615
|
210 return p;
|
Chris@1615
|
211 }
|
Chris@1612
|
212
|
Chris@1615
|
213 bool operator==(const Event &p) const {
|
Chris@1612
|
214
|
Chris@1612
|
215 if (m_frame != p.m_frame) return false;
|
Chris@1629
|
216
|
Chris@1629
|
217 if (m_haveDuration != p.m_haveDuration) return false;
|
Chris@1629
|
218 if (m_haveDuration && (m_duration != p.m_duration)) return false;
|
Chris@1612
|
219
|
Chris@1612
|
220 if (m_haveValue != p.m_haveValue) return false;
|
Chris@1612
|
221 if (m_haveValue && (m_value != p.m_value)) return false;
|
Chris@1612
|
222
|
Chris@1612
|
223 if (m_haveLevel != p.m_haveLevel) return false;
|
Chris@1612
|
224 if (m_haveLevel && (m_level != p.m_level)) return false;
|
Chris@1612
|
225
|
Chris@1612
|
226 if (m_haveReferenceFrame != p.m_haveReferenceFrame) return false;
|
Chris@1612
|
227 if (m_haveReferenceFrame &&
|
Chris@1612
|
228 (m_referenceFrame != p.m_referenceFrame)) return false;
|
Chris@1612
|
229
|
Chris@1612
|
230 if (m_label != p.m_label) return false;
|
Chris@1663
|
231 if (m_uri != p.m_uri) return false;
|
Chris@1612
|
232
|
Chris@1612
|
233 return true;
|
Chris@1612
|
234 }
|
Chris@1612
|
235
|
Chris@1630
|
236 bool operator!=(const Event &p) const {
|
Chris@1630
|
237 return !operator==(p);
|
Chris@1630
|
238 }
|
Chris@1630
|
239
|
Chris@1615
|
240 bool operator<(const Event &p) const {
|
Chris@1612
|
241
|
Chris@1629
|
242 if (m_frame != p.m_frame) {
|
Chris@1629
|
243 return m_frame < p.m_frame;
|
Chris@1629
|
244 }
|
Chris@1612
|
245
|
Chris@1615
|
246 // events without a property sort before events with that property
|
Chris@1612
|
247
|
Chris@1629
|
248 if (m_haveDuration != p.m_haveDuration) {
|
Chris@1629
|
249 return !m_haveDuration;
|
Chris@1629
|
250 }
|
Chris@1629
|
251 if (m_haveDuration && (m_duration != p.m_duration)) {
|
Chris@1629
|
252 return m_duration < p.m_duration;
|
Chris@1629
|
253 }
|
Chris@1629
|
254
|
Chris@1629
|
255 if (m_haveValue != p.m_haveValue) {
|
Chris@1629
|
256 return !m_haveValue;
|
Chris@1629
|
257 }
|
Chris@1629
|
258 if (m_haveValue && (m_value != p.m_value)) {
|
Chris@1629
|
259 return m_value < p.m_value;
|
Chris@1629
|
260 }
|
Chris@1612
|
261
|
Chris@1629
|
262 if (m_haveLevel != p.m_haveLevel) {
|
Chris@1629
|
263 return !m_haveLevel;
|
Chris@1629
|
264 }
|
Chris@1629
|
265 if (m_haveLevel && (m_level != p.m_level)) {
|
Chris@1629
|
266 return m_level < p.m_level;
|
Chris@1629
|
267 }
|
Chris@1612
|
268
|
Chris@1612
|
269 if (m_haveReferenceFrame != p.m_haveReferenceFrame) {
|
Chris@1612
|
270 return !m_haveReferenceFrame;
|
Chris@1612
|
271 }
|
Chris@1612
|
272 if (m_haveReferenceFrame && (m_referenceFrame != p.m_referenceFrame)) {
|
Chris@1612
|
273 return m_referenceFrame < p.m_referenceFrame;
|
Chris@1612
|
274 }
|
Chris@1612
|
275
|
Chris@1663
|
276 if (m_label != p.m_label) {
|
Chris@1663
|
277 return m_label < p.m_label;
|
Chris@1663
|
278 }
|
Chris@1663
|
279 return m_uri < p.m_uri;
|
Chris@1612
|
280 }
|
Chris@1612
|
281
|
Chris@1674
|
282 struct ExportNameOptions {
|
Chris@1674
|
283
|
Chris@1674
|
284 ExportNameOptions() :
|
Chris@1789
|
285 valueAttributeName("value"),
|
Chris@1789
|
286 levelAttributeName("level"),
|
Chris@1674
|
287 uriAttributeName("uri") { }
|
Chris@1674
|
288
|
Chris@1789
|
289 QString valueAttributeName;
|
Chris@1789
|
290 QString levelAttributeName;
|
Chris@1674
|
291 QString uriAttributeName;
|
Chris@1674
|
292 };
|
Chris@1674
|
293
|
Chris@1612
|
294 void toXml(QTextStream &stream,
|
Chris@1612
|
295 QString indent = "",
|
Chris@1674
|
296 QString extraAttributes = "",
|
Chris@1674
|
297 ExportNameOptions opts = ExportNameOptions()) const {
|
Chris@1612
|
298
|
Chris@1615
|
299 // For I/O purposes these are points, not events
|
Chris@1612
|
300 stream << indent << QString("<point frame=\"%1\" ").arg(m_frame);
|
Chris@1674
|
301 if (m_haveValue) {
|
Chris@1674
|
302 stream << QString("%1=\"%2\" ")
|
Chris@1789
|
303 .arg(opts.valueAttributeName).arg(m_value);
|
Chris@1674
|
304 }
|
Chris@1674
|
305 if (m_haveDuration) {
|
Chris@1674
|
306 stream << QString("duration=\"%1\" ").arg(m_duration);
|
Chris@1674
|
307 }
|
Chris@1674
|
308 if (m_haveLevel) {
|
Chris@1789
|
309 stream << QString("%1=\"%2\" ")
|
Chris@1789
|
310 .arg(opts.levelAttributeName)
|
Chris@1789
|
311 .arg(m_level);
|
Chris@1674
|
312 }
|
Chris@1674
|
313 if (m_haveReferenceFrame) {
|
Chris@1674
|
314 stream << QString("referenceFrame=\"%1\" ")
|
Chris@1674
|
315 .arg(m_referenceFrame);
|
Chris@1674
|
316 }
|
Chris@1682
|
317
|
Chris@1682
|
318 stream << QString("label=\"%1\" ")
|
Chris@1682
|
319 .arg(XmlExportable::encodeEntities(m_label));
|
Chris@1682
|
320
|
Chris@1663
|
321 if (m_uri != QString()) {
|
Chris@1674
|
322 stream << QString("%1=\"%2\" ")
|
Chris@1674
|
323 .arg(opts.uriAttributeName)
|
Chris@1663
|
324 .arg(XmlExportable::encodeEntities(m_uri));
|
Chris@1663
|
325 }
|
Chris@1641
|
326 stream << extraAttributes << "/>\n";
|
Chris@1612
|
327 }
|
Chris@1612
|
328
|
Chris@1612
|
329 QString toXmlString(QString indent = "",
|
Chris@1612
|
330 QString extraAttributes = "") const {
|
Chris@1612
|
331 QString s;
|
Chris@1612
|
332 QTextStream out(&s);
|
Chris@1612
|
333 toXml(out, indent, extraAttributes);
|
Chris@1612
|
334 out.flush();
|
Chris@1612
|
335 return s;
|
Chris@1612
|
336 }
|
Chris@1615
|
337
|
Chris@1629
|
338 NoteData toNoteData(sv_samplerate_t sampleRate,
|
Chris@1637
|
339 bool valueIsMidiPitch) const {
|
Chris@1615
|
340
|
Chris@1615
|
341 sv_frame_t duration;
|
Chris@1629
|
342 if (m_haveDuration && m_duration > 0) {
|
Chris@1615
|
343 duration = m_duration;
|
Chris@1615
|
344 } else {
|
Chris@1615
|
345 duration = sv_frame_t(sampleRate / 6); // arbitrary short duration
|
Chris@1615
|
346 }
|
Chris@1615
|
347
|
Chris@1615
|
348 int midiPitch;
|
Chris@1615
|
349 float frequency = 0.f;
|
Chris@1615
|
350 if (m_haveValue) {
|
Chris@1615
|
351 if (valueIsMidiPitch) {
|
Chris@1615
|
352 midiPitch = int(roundf(m_value));
|
Chris@1615
|
353 } else {
|
Chris@1615
|
354 frequency = m_value;
|
Chris@1615
|
355 midiPitch = Pitch::getPitchForFrequency(frequency);
|
Chris@1615
|
356 }
|
Chris@1615
|
357 } else {
|
Chris@1615
|
358 midiPitch = 64;
|
Chris@1615
|
359 valueIsMidiPitch = true;
|
Chris@1615
|
360 }
|
Chris@1615
|
361
|
Chris@1615
|
362 int velocity = 100;
|
Chris@1615
|
363 if (m_haveLevel) {
|
Chris@1615
|
364 if (m_level > 0.f && m_level <= 1.f) {
|
Chris@1615
|
365 velocity = int(roundf(m_level * 127.f));
|
Chris@1615
|
366 }
|
Chris@1615
|
367 }
|
Chris@1615
|
368
|
Chris@1615
|
369 NoteData n(m_frame, duration, midiPitch, velocity);
|
Chris@1615
|
370 n.isMidiPitchQuantized = valueIsMidiPitch;
|
Chris@1615
|
371 if (!valueIsMidiPitch) {
|
Chris@1615
|
372 n.frequency = frequency;
|
Chris@1615
|
373 }
|
Chris@1615
|
374
|
Chris@1615
|
375 return n;
|
Chris@1615
|
376 }
|
Chris@1623
|
377
|
Chris@1833
|
378 QVector<QString>
|
Chris@1833
|
379 getStringExportHeaders(DataExportOptions opts,
|
Chris@1833
|
380 ExportNameOptions nameOpts) const {
|
Chris@1815
|
381
|
Chris@1815
|
382 QStringList list;
|
Chris@1815
|
383
|
Chris@1815
|
384 // These are considered API rather than human-readable text -
|
Chris@1815
|
385 // they shouldn't be translated
|
Chris@1815
|
386
|
Chris@1815
|
387 if (opts & DataExportWriteTimeInFrames) {
|
Chris@1815
|
388 list << "frame";
|
Chris@1815
|
389 } else {
|
Chris@1815
|
390 list << "time";
|
Chris@1815
|
391 }
|
Chris@1815
|
392
|
Chris@1815
|
393 if (m_haveValue) {
|
Chris@1815
|
394 list << nameOpts.valueAttributeName;
|
Chris@1815
|
395 }
|
Chris@1815
|
396
|
Chris@1815
|
397 if (m_haveDuration) {
|
Chris@1815
|
398 list << "duration";
|
Chris@1815
|
399 }
|
Chris@1815
|
400
|
Chris@1815
|
401 if (m_haveLevel) {
|
Chris@1816
|
402 if (!(opts & DataExportOmitLevel)) {
|
Chris@1815
|
403 list << nameOpts.levelAttributeName;
|
Chris@1815
|
404 }
|
Chris@1815
|
405 }
|
Chris@1815
|
406
|
Chris@1815
|
407 if (m_uri != "") {
|
Chris@1815
|
408 list << nameOpts.uriAttributeName;
|
Chris@1815
|
409 }
|
Chris@1815
|
410
|
Chris@1815
|
411 list << "label";
|
Chris@1833
|
412
|
Chris@1833
|
413 QVector<QString> sv;
|
Chris@1833
|
414 for (QString s: list) {
|
Chris@1833
|
415 sv.push_back(s.toUpper());
|
Chris@1833
|
416 }
|
Chris@1833
|
417 return sv;
|
Chris@1833
|
418 }
|
Chris@1833
|
419
|
Chris@1833
|
420 QVector<QString>
|
Chris@1833
|
421 toStringExportRow(DataExportOptions opts,
|
Chris@1833
|
422 sv_samplerate_t sampleRate) const {
|
Chris@1815
|
423
|
Chris@1629
|
424 QStringList list;
|
Chris@1629
|
425
|
Chris@1815
|
426 if (opts & DataExportWriteTimeInFrames) {
|
Chris@1815
|
427 list << QString("%1").arg(m_frame);
|
Chris@1815
|
428 } else {
|
Chris@1815
|
429 list << RealTime::frame2RealTime(m_frame, sampleRate)
|
Chris@1815
|
430 .toString().c_str();
|
Chris@1815
|
431 }
|
Chris@1629
|
432
|
Chris@1629
|
433 if (m_haveValue) {
|
Chris@1629
|
434 list << QString("%1").arg(m_value);
|
Chris@1629
|
435 }
|
Chris@1629
|
436
|
Chris@1629
|
437 if (m_haveDuration) {
|
Chris@1815
|
438 if (opts & DataExportWriteTimeInFrames) {
|
Chris@1815
|
439 list << QString("%1").arg(m_duration);
|
Chris@1815
|
440 } else {
|
Chris@1815
|
441 list << RealTime::frame2RealTime(m_duration, sampleRate)
|
Chris@1815
|
442 .toString().c_str();
|
Chris@1815
|
443 }
|
Chris@1629
|
444 }
|
Chris@1629
|
445
|
Chris@1629
|
446 if (m_haveLevel) {
|
Chris@1816
|
447 if (!(opts & DataExportOmitLevel)) {
|
Chris@1629
|
448 list << QString("%1").arg(m_level);
|
Chris@1629
|
449 }
|
Chris@1629
|
450 }
|
Chris@1787
|
451
|
Chris@1787
|
452 // Put URI before label, to preserve the ordering previously
|
Chris@1787
|
453 // used in the custom Image model exporter. We shouldn't
|
Chris@1787
|
454 // change the column ordering unless (until?) we provide a
|
Chris@1787
|
455 // facility for the user to customise it
|
Chris@1787
|
456 if (m_uri != "") list << m_uri;
|
Chris@1629
|
457 if (m_label != "") list << m_label;
|
Chris@1833
|
458
|
Chris@1833
|
459 return list.toVector();
|
Chris@1629
|
460 }
|
Chris@1799
|
461
|
Chris@1623
|
462 uint hash(uint seed = 0) const {
|
Chris@1623
|
463 uint h = qHash(m_label, seed);
|
Chris@1623
|
464 if (m_haveValue) h ^= qHash(m_value);
|
Chris@1623
|
465 if (m_haveLevel) h ^= qHash(m_level);
|
Chris@1623
|
466 h ^= qHash(m_frame);
|
Chris@1629
|
467 if (m_haveDuration) h ^= qHash(m_duration);
|
Chris@1623
|
468 if (m_haveReferenceFrame) h ^= qHash(m_referenceFrame);
|
Chris@1663
|
469 h ^= qHash(m_uri);
|
Chris@1623
|
470 return h;
|
Chris@1623
|
471 }
|
Chris@1611
|
472
|
Chris@1611
|
473 private:
|
Chris@1611
|
474 // The order of fields here is chosen to minimise overall size of struct.
|
Chris@1612
|
475 // We potentially store very many of these objects.
|
Chris@1611
|
476 // If you change something, check what difference it makes to packing.
|
Chris@1611
|
477 bool m_haveValue : 1;
|
Chris@1611
|
478 bool m_haveLevel : 1;
|
Chris@1629
|
479 bool m_haveDuration : 1;
|
Chris@1611
|
480 bool m_haveReferenceFrame : 1;
|
Chris@1611
|
481 float m_value;
|
Chris@1611
|
482 float m_level;
|
Chris@1611
|
483 sv_frame_t m_frame;
|
Chris@1611
|
484 sv_frame_t m_duration;
|
Chris@1611
|
485 sv_frame_t m_referenceFrame;
|
Chris@1611
|
486 QString m_label;
|
Chris@1663
|
487 QString m_uri;
|
Chris@1611
|
488 };
|
Chris@1611
|
489
|
Chris@1623
|
490 inline uint qHash(const Event &e, uint seed = 0) {
|
Chris@1623
|
491 return e.hash(seed);
|
Chris@1623
|
492 }
|
Chris@1623
|
493
|
Chris@1615
|
494 typedef std::vector<Event> EventVector;
|
Chris@1612
|
495
|
Chris@1611
|
496 #endif
|