BoxModel.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 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version. See the file
12  COPYING included with this distribution for more information.
13 */
14 
15 #ifndef SV_BOX_MODEL_H
16 #define SV_BOX_MODEL_H
17 
18 #include "EventCommands.h"
19 #include "TabularModel.h"
20 #include "Model.h"
21 #include "DeferredNotifier.h"
22 
23 #include "base/RealTime.h"
24 #include "base/EventSeries.h"
25 #include "base/UnitDatabase.h"
26 
27 #include "system/System.h"
28 
29 #include <QMutex>
30 
40 class BoxModel : public Model,
41  public TabularModel,
42  public EventEditable
43 {
44  Q_OBJECT
45 
46 public:
48  int resolution,
49  bool notifyOnAdd = true) :
50  m_sampleRate(sampleRate),
51  m_resolution(resolution),
52  m_valueMinimum(0.f),
53  m_valueMaximum(0.f),
54  m_haveExtents(false),
55  m_notifier(this,
56  getId(),
57  notifyOnAdd ?
58  DeferredNotifier::NOTIFY_ALWAYS :
59  DeferredNotifier::NOTIFY_DEFERRED),
60  m_completion(100) {
61  }
62 
63  BoxModel(sv_samplerate_t sampleRate, int resolution,
64  float valueMinimum, float valueMaximum,
65  bool notifyOnAdd = true) :
66  m_sampleRate(sampleRate),
67  m_resolution(resolution),
68  m_valueMinimum(valueMinimum),
69  m_valueMaximum(valueMaximum),
70  m_haveExtents(true),
71  m_notifier(this,
72  getId(),
73  notifyOnAdd ?
74  DeferredNotifier::NOTIFY_ALWAYS :
75  DeferredNotifier::NOTIFY_DEFERRED),
76  m_completion(100) {
77  }
78 
79  virtual ~BoxModel() {
80  }
81 
82  QString getTypeName() const override { return tr("Box"); }
83  bool isSparse() const override { return true; }
84  bool isOK() const override { return true; }
85 
86  sv_frame_t getStartFrame() const override {
87  return m_events.getStartFrame();
88  }
89  sv_frame_t getTrueEndFrame() const override {
90  if (m_events.isEmpty()) return 0;
92  if (e % m_resolution == 0) return e;
93  else return (e / m_resolution + 1) * m_resolution;
94  }
95 
96  sv_samplerate_t getSampleRate() const override { return m_sampleRate; }
97  int getResolution() const { return m_resolution; }
98 
99  QString getScaleUnits() const { return m_units; }
100  void setScaleUnits(QString units) {
101  m_units = units;
103  }
104 
105  float getValueMinimum() const { return m_valueMinimum; }
106  float getValueMaximum() const { return m_valueMaximum; }
107 
108  int getCompletion() const override { return m_completion; }
109 
110  void setCompletion(int completion, bool update = true) {
111 
112  { QMutexLocker locker(&m_mutex);
113  if (m_completion == completion) return;
114  m_completion = completion;
115  }
116 
117  if (update) {
119  }
120 
121  emit completionChanged(getId());
122 
123  if (completion == 100) {
124  // henceforth:
126  emit modelChanged(getId());
127  }
128  }
129 
133  int getEventCount() const {
134  return m_events.count();
135  }
136  bool isEmpty() const {
137  return m_events.isEmpty();
138  }
139  bool containsEvent(const Event &e) const {
140  return m_events.contains(e);
141  }
143  return m_events.getAllEvents();
144  }
146  return m_events.getEventsSpanning(f, duration);
147  }
149  return m_events.getEventsCovering(f);
150  }
152  return m_events.getEventsWithin(f, duration);
153  }
155  return m_events.getEventsStartingWithin(f, duration);
156  }
158  return m_events.getEventsStartingAt(f);
159  }
161  std::function<bool(Event)> predicate,
162  EventSeries::Direction direction,
163  Event &found) const {
165  (startSearchAt, predicate, direction, found);
166  }
167 
171  void add(Event e) override {
172 
173  bool allChange = false;
174 
175  {
176  QMutexLocker locker(&m_mutex);
177  m_events.add(e);
178 
179  float f0 = e.getValue();
180  float f1 = f0 + fabsf(e.getLevel());
181 
182  if (!m_haveExtents || f0 < m_valueMinimum) {
183  m_valueMinimum = f0; allChange = true;
184  }
185  if (!m_haveExtents || f1 > m_valueMaximum) {
186  m_valueMaximum = f1; allChange = true;
187  }
188  m_haveExtents = true;
189  }
190 
192 
193  if (allChange) {
194  emit modelChanged(getId());
195  }
196  }
197 
198  void remove(Event e) override {
199  {
200  QMutexLocker locker(&m_mutex);
201  m_events.remove(e);
202  }
203  emit modelChangedWithin(getId(),
204  e.getFrame(),
205  e.getFrame() + e.getDuration() + m_resolution);
206  }
207 
212  int getRowCount() const override {
213  return m_events.count();
214  }
215 
216  int getColumnCount() const override {
217  return 6;
218  }
219 
220  bool isColumnTimeValue(int column) const override {
221  // NB duration is not a "time value" -- that's for columns
222  // whose sort ordering is exactly that of the frame time
223  return (column < 2);
224  }
225 
226  sv_frame_t getFrameForRow(int row) const override {
227  if (row < 0 || row >= m_events.count()) {
228  return 0;
229  }
230  Event e = m_events.getEventByIndex(row);
231  return e.getFrame();
232  }
233 
234  int getRowForFrame(sv_frame_t frame) const override {
235  return m_events.getIndexForEvent(Event(frame));
236  }
237 
238  QString getHeading(int column) const override {
239  switch (column) {
240  case 0: return tr("Time");
241  case 1: return tr("Frame");
242  case 2: return tr("Duration");
243  case 3: return tr("Min Freq");
244  case 4: return tr("Max Freq");
245  case 5: return tr("Label");
246  default: return tr("Unknown");
247  }
248  }
249 
250  SortType getSortType(int column) const override {
251  if (column == 5) return SortAlphabetical;
252  return SortNumeric;
253  }
254 
255  QVariant getData(int row, int column, int role) const override {
256 
257  if (row < 0 || row >= m_events.count()) {
258  return QVariant();
259  }
260 
261  Event e = m_events.getEventByIndex(row);
262 
263  switch (column) {
264  case 0: return adaptFrameForRole(e.getFrame(), getSampleRate(), role);
265  case 1: return int(e.getFrame());
266  case 2: return int(e.getDuration());
267  case 3: return adaptValueForRole(e.getValue(), getScaleUnits(), role);
268  case 4: return adaptValueForRole(e.getValue() + fabsf(e.getLevel()),
269  getScaleUnits(), role);
270  case 5: return e.getLabel();
271  default: return QVariant();
272  }
273  }
274 
275  bool isEditable() const override { return true; }
276 
277  Command *getSetDataCommand(int row, int column, const QVariant &value,
278  int role) override {
279 
280  if (row < 0 || row >= m_events.count()) return nullptr;
281  if (role != Qt::EditRole) return nullptr;
282 
283  Event e0 = m_events.getEventByIndex(row);
284  Event e1;
285 
286  switch (column) {
287  case 0: e1 = e0.withFrame(sv_frame_t(round(value.toDouble() *
288  getSampleRate()))); break;
289  case 1: e1 = e0.withFrame(value.toInt()); break;
290  case 2: e1 = e0.withDuration(value.toInt()); break;
291  case 3: e1 = e0.withValue(float(value.toDouble())); break;
292  case 4: e1 = e0.withLevel(fabsf(float(value.toDouble()) -
293  e0.getValue())); break;
294  case 5: e1 = e0.withLabel(value.toString()); break;
295  }
296 
297  auto command = new ChangeEventsCommand(getId().untyped, tr("Edit Data"));
298  command->remove(e0);
299  command->add(e1);
300  return command->finish();
301  }
302 
303  Command *getInsertRowCommand(int row) override {
304  if (row < 0 || row >= m_events.count()) return nullptr;
305  auto command = new ChangeEventsCommand(getId().untyped,
306  tr("Add Box"));
307  Event e = m_events.getEventByIndex(row);
308  command->add(e);
309  return command->finish();
310  }
311 
312  Command *getRemoveRowCommand(int row) override {
313  if (row < 0 || row >= m_events.count()) return nullptr;
314  auto command = new ChangeEventsCommand(getId().untyped,
315  tr("Delete Box"));
316  Event e = m_events.getEventByIndex(row);
317  command->remove(e);
318  return command->finish();
319  }
320 
321 
325  void toXml(QTextStream &out,
326  QString indent = "",
327  QString extraAttributes = "") const override {
328 
330  (out,
331  indent,
332  QString("type=\"sparse\" dimensions=\"2\" resolution=\"%1\" "
333  "notifyOnAdd=\"%2\" dataset=\"%3\" subtype=\"%4\" "
334  "minimum=\"%5\" maximum=\"%6\" units=\"%7\" %8")
335  .arg(m_resolution)
336  .arg("true") // always true after model reaches 100% -
337  // subsequent events are always notified
338  .arg(m_events.getExportId())
339  .arg("box")
340  .arg(m_valueMinimum)
341  .arg(m_valueMaximum)
342  .arg(encodeEntities(m_units))
343  .arg(extraAttributes));
344 
345  Event::ExportNameOptions options;
346  options.levelAttributeName = "extent";
347 
348  m_events.toXml(out, indent, QString("dimensions=\"2\""), options);
349  }
350 
351  QVector<QString>
353 
354  QStringList list;
355 
356  // These are considered API rather than human-readable text -
357  // they shouldn't be translated
358 
359  if (opts & DataExportWriteTimeInFrames) {
360  list << "startframe" << "endframe";
361  } else {
362  list << "start" << "end";
363  }
364 
365  list << "extent start" << "extent end" << "label";
366 
367  QVector<QString> sv;
368  for (QString s: list) {
369  sv.push_back(s.toUpper());
370  }
371  return sv;
372  }
373 
374  QVector<QVector<QString>>
376  sv_frame_t startFrame,
377  sv_frame_t duration) const override {
378 
379  // We need a custom format here
380 
381  EventVector ee = m_events.getEventsSpanning(startFrame, duration);
382 
383  QVector<QVector<QString>> rows;
384 
385  for (auto e: ee) {
386 
387  QVector<QString> list;
388 
389  if (opts & DataExportWriteTimeInFrames) {
390 
391  list << QString("%1").arg(e.getFrame());
392  list << QString("%1").arg(e.getFrame() + e.getDuration());
393 
394  } else {
395 
397  (e.getFrame(), getSampleRate())
398  .toString().c_str();
399 
401  (e.getFrame() + e.getDuration(), getSampleRate())
402  .toString().c_str();
403  }
404 
405  list << QString("%1").arg(e.getValue());
406 
407  list << QString("%1").arg(e.getValue() + fabsf(e.getLevel()));
408 
409  if (e.getLabel() != "") {
410  list << e.getLabel();
411  }
412 
413  rows.push_back(list);
414  }
415 
416  return rows;
417  }
418 
419 protected:
422 
426  QString m_units;
429 
431 
432  mutable QMutex m_mutex;
433 };
434 
435 #endif
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
Stream this exportable object out to XML on a text stream.
Definition: Model.cpp:204
Command * getSetDataCommand(int row, int column, const QVariant &value, int role) override
Return a command to set the value in the given cell, for the given role, to the contents of the suppl...
Definition: BoxModel.h:277
bool m_haveExtents
Definition: BoxModel.h:425
QString getHeading(int column) const override
Return the heading for a given column, e.g.
Definition: BoxModel.h:238
bool contains(const Event &e) const
float getValue() const
Definition: Event.h:122
int getRowForFrame(sv_frame_t frame) const override
Return the number of the first row whose frame time is not less than the given one.
Definition: BoxModel.h:234
EventSeries m_events
Definition: BoxModel.h:430
int count() const
Definition: EventSeries.cpp:79
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
int getRowCount() const override
TabularModel methods.
Definition: BoxModel.h:212
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
void add(const Event &e)
Definition: EventSeries.cpp:89
void registerUnit(QString unit)
Command * getInsertRowCommand(int row) override
Return a command to insert a new row before the row with the given index.
Definition: BoxModel.h:303
EventVector getEventsStartingAt(sv_frame_t frame) const
Retrieve all events starting at exactly the given frame.
Definition: EventSeries.h:143
static QVariant adaptFrameForRole(sv_frame_t frame, sv_samplerate_t rate, int role)
Definition: TabularModel.h:124
QString getScaleUnits() const
Definition: BoxModel.h:99
sv_frame_t getFrameForRow(int row) const override
Return the frame time for the given row.
Definition: BoxModel.h:226
EventVector getEventsWithin(sv_frame_t f, sv_frame_t duration) const
Definition: BoxModel.h:151
bool containsEvent(const Event &e) const
Definition: BoxModel.h:139
Event getEventByIndex(int index) const
Return the event at the given numerical index in the series, where 0 = the first event and count()-1 ...
void update(sv_frame_t frame, sv_frame_t duration)
EventVector getAllEvents() const
Retrieve all events, in their natural order.
QString m_units
Definition: BoxModel.h:426
int getEventCount() const
Query methods.
Definition: BoxModel.h:133
sv_frame_t getTrueEndFrame() const override
Return the audio frame at the end of the model.
Definition: BoxModel.h:89
QVector< QVector< QString > > toStringExportRows(DataExportOptions opts, sv_frame_t startFrame, sv_frame_t duration) const override
Emit events starting within the given range as string rows ready for conversion to an e...
Definition: BoxModel.h:375
int getColumnCount() const override
Return the number of columns (values/labels/etc per item).
Definition: BoxModel.h:216
sv_frame_t getStartFrame() const
Return the frame of the first event in the series.
EventVector getEventsStartingWithin(sv_frame_t f, sv_frame_t duration) const
Definition: BoxModel.h:154
float getValueMaximum() const
Definition: BoxModel.h:106
int getCompletion() const override
Return an estimated percentage value showing how far through any background operation used to calcula...
Definition: BoxModel.h:108
sv_frame_t getStartFrame() const override
Return the first audio frame spanned by the model.
Definition: BoxModel.h:86
BoxModel(sv_samplerate_t sampleRate, int resolution, bool notifyOnAdd=true)
Definition: BoxModel.h:47
void makeDeferredNotifications()
Id getId() const
Return an id for this object.
Definition: ById.h:193
int getIndexForEvent(const Event &e) const
Return the index of the first event in the series that does not compare inferior to the given event...
QString getTypeName() const override
Return the type of the model.
Definition: BoxModel.h:82
Event withLabel(QString label) const
Definition: Event.h:160
float m_valueMinimum
Definition: BoxModel.h:423
void toXml(QTextStream &out, QString indent, QString extraAttributes) const override
Emit to XML as a dataset element.
static QString encodeEntities(QString)
EventVector getEventsStartingAt(sv_frame_t f) const
Definition: BoxModel.h:157
sv_frame_t getDuration() const
Definition: Event.h:138
EventVector getEventsSpanning(sv_frame_t f, sv_frame_t duration) const
Definition: BoxModel.h:145
bool isEmpty() const
Definition: EventSeries.cpp:72
QVariant getData(int row, int column, int role) const override
Get the value in the given cell, for the given role.
Definition: BoxModel.h:255
EventVector getEventsCovering(sv_frame_t frame) const
Retrieve all events that cover the given frame.
bool getNearestEventMatching(sv_frame_t startSearchAt, std::function< bool(Event)> predicate, EventSeries::Direction direction, Event &found) const
Definition: BoxModel.h:160
virtual ~BoxModel()
Definition: BoxModel.h:79
static QVariant adaptValueForRole(float value, QString unit, int role)
Definition: TabularModel.h:133
BoxModel(sv_samplerate_t sampleRate, int resolution, float valueMinimum, float valueMaximum, bool notifyOnAdd=true)
Definition: BoxModel.h:63
int getResolution() const
Definition: BoxModel.h:97
QMutex m_mutex
Definition: BoxModel.h:432
static UnitDatabase * getInstance()
void add(Event e) override
Editing methods.
Definition: BoxModel.h:171
EventVector getEventsSpanning(sv_frame_t frame, sv_frame_t duration) const
Retrieve all events any part of which falls within the range in frames defined by the given frame f a...
Event withDuration(sv_frame_t duration) const
Definition: Event.h:140
int m_resolution
Definition: BoxModel.h:421
float getValueMinimum() const
Definition: BoxModel.h:105
Command * getRemoveRowCommand(int row) override
Return a command to delete the row with the given index.
Definition: BoxModel.h:312
QVector< QString > getStringExportHeaders(DataExportOptions opts) const override
Return a label for each column that would be written by toStringExportRows.
Definition: BoxModel.h:352
sv_samplerate_t m_sampleRate
Definition: BoxModel.h:420
Model is the base class for all data models that represent any sort of data on a time scale based on ...
Definition: Model.h:51
TabularModel is an abstract base class for models that support direct access to data in a tabular for...
Definition: TabularModel.h:35
void completionChanged(ModelId myId)
Emitted when some internal processing has advanced a stage, but the model has not changed externally...
BoxModel – a model for annotations having start time, duration, and a value range.
Definition: BoxModel.h:40
Event withValue(float value) const
Definition: Event.h:124
sv_frame_t getEndFrame() const
Return the frame plus duration of the event in the series that ends last.
Event withFrame(sv_frame_t frame) const
Definition: Event.h:115
void remove(const Event &e)
ExportId getExportId() const
Return the numerical export identifier for this object.
QString levelAttributeName
Definition: Event.h:290
bool getNearestEventMatching(sv_frame_t startSearchAt, std::function< bool(const Event &)> predicate, Direction direction, Event &found) const
Return the first event for which the given predicate returns true, searching events with start frames...
void setScaleUnits(QString units)
Definition: BoxModel.h:100
EventVector getAllEvents() const
Definition: BoxModel.h:142
void modelChangedWithin(ModelId myId, sv_frame_t startFrame, sv_frame_t endFrame)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
EventVector getEventsWithin(sv_frame_t frame, sv_frame_t duration, int overspill=0) const
Retrieve all events falling wholly within the range in frames defined by the given frame f and durati...
Event withLevel(float level) const
Definition: Event.h:178
bool isEditable() const override
Return true if the model is user-editable, false otherwise.
Definition: BoxModel.h:275
bool isSparse() const override
Return true if this is a sparse model.
Definition: BoxModel.h:83
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
sv_frame_t getFrame() const
Definition: Event.h:113
Container storing a series of events, with or without durations, and supporting the ability to query ...
Definition: EventSeries.h:49
void setCompletion(int completion, bool update=true)
Definition: BoxModel.h:110
bool isEmpty() const
Definition: BoxModel.h:136
DeferredNotifier m_notifier
Definition: BoxModel.h:427
void switchMode(Mode newMode)
SortType getSortType(int column) const override
Return the sort type (numeric or alphabetical) for the column.
Definition: BoxModel.h:250
float m_valueMaximum
Definition: BoxModel.h:424
std::vector< Event > EventVector
Definition: Event.h:494
EventVector getEventsCovering(sv_frame_t f) const
Definition: BoxModel.h:148
Interface for classes that can be modified through these commands.
Definition: EventCommands.h:26
void toXml(QTextStream &out, QString indent="", QString extraAttributes="") const override
XmlExportable methods.
Definition: BoxModel.h:325
Use sample frames rather than seconds for time and duration values.
QString getLabel() const
Definition: Event.h:158
bool isColumnTimeValue(int column) const override
Return true if the column is the frame time of the item, or an alternative representation of it (i...
Definition: BoxModel.h:220
EventVector getEventsStartingWithin(sv_frame_t frame, sv_frame_t duration) const
Retrieve all events starting within the range in frames defined by the given frame f and duration d...
sv_samplerate_t getSampleRate() const override
Return the frame rate in frames per second.
Definition: BoxModel.h:96
void modelChanged(ModelId myId)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
bool isOK() const override
Return true if the model was constructed successfully.
Definition: BoxModel.h:84
int m_completion
Definition: BoxModel.h:428
Command to add or remove a series of events to or from an editable, with undo.
int DataExportOptions