Event.h
Go to the documentation of this file.
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 Chris Cannam.
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 SV_EVENT_H
17 #define SV_EVENT_H
18 
19 #include "BaseTypes.h"
20 #include "NoteData.h"
21 #include "XmlExportable.h"
22 #include "DataExportOptions.h"
23 
24 #include <vector>
25 #include <stdexcept>
26 
27 #include <QString>
28 
29 #if (QT_VERSION < QT_VERSION_CHECK(5, 3, 0))
30 #ifdef __GNUC__
31 #pragma GCC diagnostic ignored "-Wunused-function"
32 #endif
33 static uint qHash(float key, uint seed = 0) {
34  uint h = seed;
35  const uchar *p = reinterpret_cast<const uchar *>(&key);
36  for (size_t i = 0; i < sizeof(key); ++i) {
37  h = 31 * h + p[i];
38  }
39  return h;
40 }
41 #endif
42 
55 class Event
56 {
57 public:
58  Event() :
59  m_haveValue(false), m_haveLevel(false),
60  m_haveDuration(false), m_haveReferenceFrame(false),
61  m_value(0.f), m_level(0.f), m_frame(0),
62  m_duration(0), m_referenceFrame(0), m_label() { }
63 
64  Event(sv_frame_t frame) :
65  m_haveValue(false), m_haveLevel(false),
66  m_haveDuration(false), m_haveReferenceFrame(false),
67  m_value(0.f), m_level(0.f), m_frame(frame),
68  m_duration(0), m_referenceFrame(0), m_label() { }
69 
70  Event(sv_frame_t frame, QString label) :
71  m_haveValue(false), m_haveLevel(false),
72  m_haveDuration(false), m_haveReferenceFrame(false),
73  m_value(0.f), m_level(0.f), m_frame(frame),
74  m_duration(0), m_referenceFrame(0), m_label(label) { }
75 
76  Event(sv_frame_t frame, float value, QString label) :
77  m_haveValue(true), m_haveLevel(false),
78  m_haveDuration(false), m_haveReferenceFrame(false),
79  m_value(value), m_level(0.f), m_frame(frame),
80  m_duration(0), m_referenceFrame(0), m_label(label) { }
81 
82  Event(sv_frame_t frame, float value, sv_frame_t duration, QString label) :
83  m_haveValue(true), m_haveLevel(false),
85  m_value(value), m_level(0.f), m_frame(frame),
86  m_duration(duration), m_referenceFrame(0), m_label(label) {
87  if (m_duration < 0) {
90  }
91  }
92 
93  Event(sv_frame_t frame, float value, sv_frame_t duration,
94  float level, QString label) :
95  m_haveValue(true), m_haveLevel(true),
97  m_value(value), m_level(level), m_frame(frame),
98  m_duration(duration), m_referenceFrame(0), m_label(label) {
99  if (m_duration < 0) {
100  m_frame += m_duration;
102  }
103  }
104 
105  Event(const Event &event) =default;
106 
107  // We would ideally like Event to be immutable - but we have to
108  // have these because otherwise we can't put Events in vectors
109  // etc. Let's call it conceptually immutable
110  Event &operator=(const Event &event) =default;
111  Event &operator=(Event &&event) =default;
112 
113  sv_frame_t getFrame() const { return m_frame; }
114 
115  Event withFrame(sv_frame_t frame) const {
116  Event p(*this);
117  p.m_frame = frame;
118  return p;
119  }
120 
121  bool hasValue() const { return m_haveValue; }
122  float getValue() const { return m_haveValue ? m_value : 0.f; }
123 
124  Event withValue(float value) const {
125  Event p(*this);
126  p.m_haveValue = true;
127  p.m_value = value;
128  return p;
129  }
130  Event withoutValue() const {
131  Event p(*this);
132  p.m_haveValue = false;
133  p.m_value = 0.f;
134  return p;
135  }
136 
137  bool hasDuration() const { return m_haveDuration; }
139 
140  Event withDuration(sv_frame_t duration) const {
141  Event p(*this);
142  p.m_duration = duration;
143  p.m_haveDuration = true;
144  if (p.m_duration < 0) {
145  p.m_frame += p.m_duration;
146  p.m_duration = -p.m_duration;
147  }
148  return p;
149  }
151  Event p(*this);
152  p.m_haveDuration = false;
153  p.m_duration = 0;
154  return p;
155  }
156 
157  bool hasLabel() const { return m_label != QString(); }
158  QString getLabel() const { return m_label; }
159 
160  Event withLabel(QString label) const {
161  Event p(*this);
162  p.m_label = label;
163  return p;
164  }
165 
166  bool hasUri() const { return m_uri != QString(); }
167  QString getURI() const { return m_uri; }
168 
169  Event withURI(QString uri) const {
170  Event p(*this);
171  p.m_uri = uri;
172  return p;
173  }
174 
175  bool hasLevel() const { return m_haveLevel; }
176  float getLevel() const { return m_haveLevel ? m_level : 0.f; }
177 
178  Event withLevel(float level) const {
179  Event p(*this);
180  p.m_haveLevel = true;
181  p.m_level = level;
182  return p;
183  }
184  Event withoutLevel() const {
185  Event p(*this);
186  p.m_haveLevel = false;
187  p.m_level = 0.f;
188  return p;
189  }
190 
191  bool hasReferenceFrame() const { return m_haveReferenceFrame; }
194  }
195 
196  bool referenceFrameDiffers() const { // from event frame
198  }
199 
201  Event p(*this);
202  p.m_haveReferenceFrame = true;
203  p.m_referenceFrame = frame;
204  return p;
205  }
207  Event p(*this);
208  p.m_haveReferenceFrame = false;
209  p.m_referenceFrame = 0;
210  return p;
211  }
212 
213  bool operator==(const Event &p) const {
214 
215  if (m_frame != p.m_frame) return false;
216 
217  if (m_haveDuration != p.m_haveDuration) return false;
218  if (m_haveDuration && (m_duration != p.m_duration)) return false;
219 
220  if (m_haveValue != p.m_haveValue) return false;
221  if (m_haveValue && (m_value != p.m_value)) return false;
222 
223  if (m_haveLevel != p.m_haveLevel) return false;
224  if (m_haveLevel && (m_level != p.m_level)) return false;
225 
226  if (m_haveReferenceFrame != p.m_haveReferenceFrame) return false;
227  if (m_haveReferenceFrame &&
228  (m_referenceFrame != p.m_referenceFrame)) return false;
229 
230  if (m_label != p.m_label) return false;
231  if (m_uri != p.m_uri) return false;
232 
233  return true;
234  }
235 
236  bool operator!=(const Event &p) const {
237  return !operator==(p);
238  }
239 
240  bool operator<(const Event &p) const {
241 
242  if (m_frame != p.m_frame) {
243  return m_frame < p.m_frame;
244  }
245 
246  // events without a property sort before events with that property
247 
248  if (m_haveDuration != p.m_haveDuration) {
249  return !m_haveDuration;
250  }
251  if (m_haveDuration && (m_duration != p.m_duration)) {
252  return m_duration < p.m_duration;
253  }
254 
255  if (m_haveValue != p.m_haveValue) {
256  return !m_haveValue;
257  }
258  if (m_haveValue && (m_value != p.m_value)) {
259  return m_value < p.m_value;
260  }
261 
262  if (m_haveLevel != p.m_haveLevel) {
263  return !m_haveLevel;
264  }
265  if (m_haveLevel && (m_level != p.m_level)) {
266  return m_level < p.m_level;
267  }
268 
270  return !m_haveReferenceFrame;
271  }
274  }
275 
276  if (m_label != p.m_label) {
277  return m_label < p.m_label;
278  }
279  return m_uri < p.m_uri;
280  }
281 
283 
285  valueAttributeName("value"),
286  levelAttributeName("level"),
287  uriAttributeName("uri") { }
288 
292  };
293 
294  void toXml(QTextStream &stream,
295  QString indent = "",
296  QString extraAttributes = "",
297  ExportNameOptions opts = ExportNameOptions()) const {
298 
299  // For I/O purposes these are points, not events
300  stream << indent << QString("<point frame=\"%1\" ").arg(m_frame);
301  if (m_haveValue) {
302  stream << QString("%1=\"%2\" ")
303  .arg(opts.valueAttributeName).arg(m_value);
304  }
305  if (m_haveDuration) {
306  stream << QString("duration=\"%1\" ").arg(m_duration);
307  }
308  if (m_haveLevel) {
309  stream << QString("%1=\"%2\" ")
310  .arg(opts.levelAttributeName)
311  .arg(m_level);
312  }
313  if (m_haveReferenceFrame) {
314  stream << QString("referenceFrame=\"%1\" ")
315  .arg(m_referenceFrame);
316  }
317 
318  stream << QString("label=\"%1\" ")
320 
321  if (m_uri != QString()) {
322  stream << QString("%1=\"%2\" ")
323  .arg(opts.uriAttributeName)
325  }
326  stream << extraAttributes << "/>\n";
327  }
328 
329  QString toXmlString(QString indent = "",
330  QString extraAttributes = "") const {
331  QString s;
332  QTextStream out(&s);
333  toXml(out, indent, extraAttributes);
334  out.flush();
335  return s;
336  }
337 
339  bool valueIsMidiPitch) const {
340 
341  sv_frame_t duration;
342  if (m_haveDuration && m_duration > 0) {
343  duration = m_duration;
344  } else {
345  duration = sv_frame_t(sampleRate / 6); // arbitrary short duration
346  }
347 
348  int midiPitch;
349  float frequency = 0.f;
350  if (m_haveValue) {
351  if (valueIsMidiPitch) {
352  midiPitch = int(roundf(m_value));
353  } else {
354  frequency = m_value;
355  midiPitch = Pitch::getPitchForFrequency(frequency);
356  }
357  } else {
358  midiPitch = 64;
359  valueIsMidiPitch = true;
360  }
361 
362  int velocity = 100;
363  if (m_haveLevel) {
364  if (m_level > 0.f && m_level <= 1.f) {
365  velocity = int(roundf(m_level * 127.f));
366  }
367  }
368 
369  NoteData n(m_frame, duration, midiPitch, velocity);
370  n.isMidiPitchQuantized = valueIsMidiPitch;
371  if (!valueIsMidiPitch) {
372  n.frequency = frequency;
373  }
374 
375  return n;
376  }
377 
378  QVector<QString>
380  ExportNameOptions nameOpts) const {
381 
382  QStringList list;
383 
384  // These are considered API rather than human-readable text -
385  // they shouldn't be translated
386 
387  if (opts & DataExportWriteTimeInFrames) {
388  list << "frame";
389  } else {
390  list << "time";
391  }
392 
393  if (m_haveValue) {
394  list << nameOpts.valueAttributeName;
395  }
396 
397  if (m_haveDuration) {
398  list << "duration";
399  }
400 
401  if (m_haveLevel) {
402  if (!(opts & DataExportOmitLevel)) {
403  list << nameOpts.levelAttributeName;
404  }
405  }
406 
407  if (m_uri != "") {
408  list << nameOpts.uriAttributeName;
409  }
410 
411  list << "label";
412 
413  QVector<QString> sv;
414  for (QString s: list) {
415  sv.push_back(s.toUpper());
416  }
417  return sv;
418  }
419 
420  QVector<QString>
422  sv_samplerate_t sampleRate) const {
423 
424  QStringList list;
425 
426  if (opts & DataExportWriteTimeInFrames) {
427  list << QString("%1").arg(m_frame);
428  } else {
429  list << RealTime::frame2RealTime(m_frame, sampleRate)
430  .toString().c_str();
431  }
432 
433  if (m_haveValue) {
434  list << QString("%1").arg(m_value);
435  }
436 
437  if (m_haveDuration) {
438  if (opts & DataExportWriteTimeInFrames) {
439  list << QString("%1").arg(m_duration);
440  } else {
441  list << RealTime::frame2RealTime(m_duration, sampleRate)
442  .toString().c_str();
443  }
444  }
445 
446  if (m_haveLevel) {
447  if (!(opts & DataExportOmitLevel)) {
448  list << QString("%1").arg(m_level);
449  }
450  }
451 
452  // Put URI before label, to preserve the ordering previously
453  // used in the custom Image model exporter. We shouldn't
454  // change the column ordering unless (until?) we provide a
455  // facility for the user to customise it
456  if (m_uri != "") list << m_uri;
457  if (m_label != "") list << m_label;
458 
459  return list.toVector();
460  }
461 
462  uint hash(uint seed = 0) const {
463  uint h = qHash(m_label, seed);
464  if (m_haveValue) h ^= qHash(m_value);
465  if (m_haveLevel) h ^= qHash(m_level);
466  h ^= qHash(m_frame);
467  if (m_haveDuration) h ^= qHash(m_duration);
469  h ^= qHash(m_uri);
470  return h;
471  }
472 
473 private:
474  // The order of fields here is chosen to minimise overall size of struct.
475  // We potentially store very many of these objects.
476  // If you change something, check what difference it makes to packing.
477  bool m_haveValue : 1;
478  bool m_haveLevel : 1;
479  bool m_haveDuration : 1;
481  float m_value;
482  float m_level;
486  QString m_label;
487  QString m_uri;
488 };
489 
490 inline uint qHash(const Event &e, uint seed = 0) {
491  return e.hash(seed);
492 }
493 
494 typedef std::vector<Event> EventVector;
495 
496 #endif
Event(sv_frame_t frame, float value, sv_frame_t duration, float level, QString label)
Definition: Event.h:93
float m_level
Definition: Event.h:482
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
sv_frame_t m_referenceFrame
Definition: Event.h:485
bool hasLevel() const
Definition: Event.h:175
float frequency
Definition: NoteData.h:34
Event & operator=(const Event &event)=default
sv_frame_t m_duration
Definition: Event.h:484
Note record used when constructing synthetic events for sonification.
Definition: NoteData.h:25
bool hasUri() const
Definition: Event.h:166
Event withURI(QString uri) const
Definition: Event.h:169
float getValue() const
Definition: Event.h:122
QString toXmlString(QString indent="", QString extraAttributes="") const
Definition: Event.h:329
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
static RealTime frame2RealTime(sv_frame_t frame, sv_samplerate_t sampleRate)
Convert a sample frame at the given sample rate into a RealTime.
Definition: RealTimeSV.cpp:498
QVector< QString > getStringExportHeaders(DataExportOptions opts, ExportNameOptions nameOpts) const
Definition: Event.h:379
bool isMidiPitchQuantized
Definition: NoteData.h:35
uint hash(uint seed=0) const
Definition: Event.h:462
Omit the level attribute from exported events.
Event(sv_frame_t frame)
Definition: Event.h:64
sv_frame_t getReferenceFrame() const
Definition: Event.h:192
uint qHash(const Event &e, uint seed=0)
Definition: Event.h:490
QString m_label
Definition: Event.h:486
Event(sv_frame_t frame, QString label)
Definition: Event.h:70
bool operator==(const Event &p) const
Definition: Event.h:213
bool hasLabel() const
Definition: Event.h:157
std::string toString(bool align=false) const
Return a human-readable debug-type string to full precision (probably not a format to show to a user ...
Definition: RealTimeSV.cpp:213
QString m_uri
Definition: Event.h:487
bool m_haveValue
Definition: Event.h:477
bool operator!=(const Event &p) const
Definition: Event.h:236
QString valueAttributeName
Definition: Event.h:289
bool hasValue() const
Definition: Event.h:121
Event withLabel(QString label) const
Definition: Event.h:160
static QString encodeEntities(QString)
QVector< QString > toStringExportRow(DataExportOptions opts, sv_samplerate_t sampleRate) const
Definition: Event.h:421
sv_frame_t getDuration() const
Definition: Event.h:138
QString uriAttributeName
Definition: Event.h:291
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="", ExportNameOptions opts=ExportNameOptions()) const
Definition: Event.h:294
Event withDuration(sv_frame_t duration) const
Definition: Event.h:140
Event withoutLevel() const
Definition: Event.h:184
sv_frame_t m_frame
Definition: Event.h:483
Event withoutDuration() const
Definition: Event.h:150
Event withValue(float value) const
Definition: Event.h:124
Event withFrame(sv_frame_t frame) const
Definition: Event.h:115
float m_value
Definition: Event.h:481
bool operator<(const Event &p) const
Definition: Event.h:240
bool m_haveLevel
Definition: Event.h:478
QString levelAttributeName
Definition: Event.h:290
Event(sv_frame_t frame, float value, QString label)
Definition: Event.h:76
Event(sv_frame_t frame, float value, sv_frame_t duration, QString label)
Definition: Event.h:82
Event withLevel(float level) const
Definition: Event.h:178
Event()
Definition: Event.h:58
bool hasReferenceFrame() const
Definition: Event.h:191
An immutable(-ish) type used for point and event representation in sparse models, as well as for inte...
Definition: Event.h:55
float getLevel() const
Definition: Event.h:176
NoteData toNoteData(sv_samplerate_t sampleRate, bool valueIsMidiPitch) const
Definition: Event.h:338
sv_frame_t getFrame() const
Definition: Event.h:113
QString getURI() const
Definition: Event.h:167
Event withoutReferenceFrame() const
Definition: Event.h:206
bool m_haveDuration
Definition: Event.h:479
static int getPitchForFrequency(double frequency, double *centsOffsetReturn=0, double concertA=0.0)
Return the nearest MIDI pitch to the given frequency.
Definition: Pitch.cpp:35
bool hasDuration() const
Definition: Event.h:137
std::vector< Event > EventVector
Definition: Event.h:494
bool m_haveReferenceFrame
Definition: Event.h:480
Use sample frames rather than seconds for time and duration values.
QString getLabel() const
Definition: Event.h:158
bool referenceFrameDiffers() const
Definition: Event.h:196
Event withReferenceFrame(sv_frame_t frame) const
Definition: Event.h:200
int DataExportOptions
Event withoutValue() const
Definition: Event.h:130