RegionModel.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_REGION_MODEL_H
16 #define SV_REGION_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 
33 class RegionModel : public Model,
34  public TabularModel,
35  public EventEditable
36 {
37  Q_OBJECT
38 
39 public:
41  int resolution,
42  bool notifyOnAdd = true) :
43  m_sampleRate(sampleRate),
44  m_resolution(resolution),
45  m_valueMinimum(0.f),
46  m_valueMaximum(0.f),
47  m_haveExtents(false),
49  m_haveDistinctValues(false),
50  m_notifier(this,
51  getId(),
52  notifyOnAdd ?
53  DeferredNotifier::NOTIFY_ALWAYS :
54  DeferredNotifier::NOTIFY_DEFERRED),
55  m_completion(100) {
56  }
57 
58  RegionModel(sv_samplerate_t sampleRate, int resolution,
59  float valueMinimum, float valueMaximum,
60  bool notifyOnAdd = true) :
61  m_sampleRate(sampleRate),
62  m_resolution(resolution),
63  m_valueMinimum(valueMinimum),
64  m_valueMaximum(valueMaximum),
65  m_haveExtents(true),
67  m_haveDistinctValues(false),
68  m_notifier(this,
69  getId(),
70  notifyOnAdd ?
71  DeferredNotifier::NOTIFY_ALWAYS :
72  DeferredNotifier::NOTIFY_DEFERRED),
73  m_completion(100) {
74  }
75 
76  virtual ~RegionModel() {
77  }
78 
79  QString getTypeName() const override { return tr("Region"); }
80  bool isSparse() const override { return true; }
81  bool isOK() const override { return true; }
82 
83  sv_frame_t getStartFrame() const override {
84  return m_events.getStartFrame();
85  }
86  sv_frame_t getTrueEndFrame() const override {
87  if (m_events.isEmpty()) return 0;
89  if (e % m_resolution == 0) return e;
90  else return (e / m_resolution + 1) * m_resolution;
91  }
92 
93  sv_samplerate_t getSampleRate() const override { return m_sampleRate; }
94  int getResolution() const { return m_resolution; }
95 
96  QString getScaleUnits() const { return m_units; }
97  void setScaleUnits(QString units) {
98  m_units = units;
100  }
101 
102  float getValueQuantization() const { return m_valueQuantization; }
104 
105  bool haveDistinctValues() const { return m_haveDistinctValues; }
106 
107  float getValueMinimum() const { return m_valueMinimum; }
108  float getValueMaximum() const { return m_valueMaximum; }
109 
110  int getCompletion() const override { return m_completion; }
111 
112  void setCompletion(int completion, bool update = true) {
113 
114  { if (m_completion == completion) return;
115  m_completion = completion;
116  }
117 
118  if (update) {
120  }
121 
122  emit completionChanged(getId());
123 
124  if (completion == 100) {
125  // henceforth:
127  emit modelChanged(getId());
128  }
129  }
130 
134  int getEventCount() const {
135  return m_events.count();
136  }
137  bool isEmpty() const {
138  return m_events.isEmpty();
139  }
140  bool containsEvent(const Event &e) const {
141  return m_events.contains(e);
142  }
144  return m_events.getAllEvents();
145  }
147  return m_events.getEventsSpanning(f, duration);
148  }
150  return m_events.getEventsCovering(f);
151  }
153  return m_events.getEventsWithin(f, duration);
154  }
156  return m_events.getEventsStartingWithin(f, duration);
157  }
159  return m_events.getEventsStartingAt(f);
160  }
162  std::function<bool(Event)> predicate,
163  EventSeries::Direction direction,
164  Event &found) const {
166  (startSearchAt, predicate, direction, found);
167  }
168 
172  void add(Event e) override {
173 
174  bool allChange = false;
175 
176  m_events.add(e);
177 
178  float v = e.getValue();
179  if (!ISNAN(v) && !ISINF(v)) {
180  if (!m_haveExtents || v < m_valueMinimum) {
181  m_valueMinimum = v; allChange = true;
182  }
183  if (!m_haveExtents || v > m_valueMaximum) {
184  m_valueMaximum = v; allChange = true;
185  }
186  m_haveExtents = true;
187  }
188 
189  if (e.hasValue() && e.getValue() != 0.f) {
190  m_haveDistinctValues = true;
191  }
192 
194 
195  if (allChange) {
196  emit modelChanged(getId());
197  }
198  }
199 
200  void remove(Event e) override {
201  m_events.remove(e);
202  emit modelChangedWithin(getId(),
203  e.getFrame(),
204  e.getFrame() + e.getDuration() + m_resolution);
205  }
206 
211  int getRowCount() const override {
212  return m_events.count();
213  }
214 
215  int getColumnCount() const override {
216  return 5;
217  }
218 
219  bool isColumnTimeValue(int column) const override {
220  // NB duration is not a "time value" -- that's for columns
221  // whose sort ordering is exactly that of the frame time
222  return (column < 2);
223  }
224 
225  sv_frame_t getFrameForRow(int row) const override {
226  if (row < 0 || row >= m_events.count()) {
227  return 0;
228  }
229  Event e = m_events.getEventByIndex(row);
230  return e.getFrame();
231  }
232 
233  int getRowForFrame(sv_frame_t frame) const override {
234  return m_events.getIndexForEvent(Event(frame));
235  }
236 
237  QString getHeading(int column) const override {
238  switch (column) {
239  case 0: return tr("Time");
240  case 1: return tr("Frame");
241  case 2: return tr("Value");
242  case 3: return tr("Duration");
243  case 4: return tr("Label");
244  default: return tr("Unknown");
245  }
246  }
247 
248  SortType getSortType(int column) const override {
249  if (column == 4) return SortAlphabetical;
250  return SortNumeric;
251  }
252 
253  QVariant getData(int row, int column, int role) const override {
254 
255  if (row < 0 || row >= m_events.count()) {
256  return QVariant();
257  }
258 
259  Event e = m_events.getEventByIndex(row);
260 
261  switch (column) {
262  case 0: return adaptFrameForRole(e.getFrame(), getSampleRate(), role);
263  case 1: return int(e.getFrame());
264  case 2: return adaptValueForRole(e.getValue(), getScaleUnits(), role);
265  case 3: return int(e.getDuration());
266  case 4: return e.getLabel();
267  default: return QVariant();
268  }
269  }
270 
271  bool isEditable() const override { return true; }
272 
273  Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override {
274 
275  if (row < 0 || row >= m_events.count()) return nullptr;
276  if (role != Qt::EditRole) return nullptr;
277 
278  Event e0 = m_events.getEventByIndex(row);
279  Event e1;
280 
281  switch (column) {
282  case 0: e1 = e0.withFrame(sv_frame_t(round(value.toDouble() *
283  getSampleRate()))); break;
284  case 1: e1 = e0.withFrame(value.toInt()); break;
285  case 2: e1 = e0.withValue(float(value.toDouble())); break;
286  case 3: e1 = e0.withDuration(value.toInt()); break;
287  case 4: e1 = e0.withLabel(value.toString()); break;
288  }
289 
290  auto command = new ChangeEventsCommand(getId().untyped, tr("Edit Data"));
291  command->remove(e0);
292  command->add(e1);
293  return command->finish();
294  }
295 
296  Command *getInsertRowCommand(int row) override {
297  if (row < 0 || row >= m_events.count()) return nullptr;
298  auto command = new ChangeEventsCommand(getId().untyped,
299  tr("Add Region"));
300  Event e = m_events.getEventByIndex(row);
301  command->add(e);
302  return command->finish();
303  }
304 
305  Command *getRemoveRowCommand(int row) override {
306  if (row < 0 || row >= m_events.count()) return nullptr;
307  auto command = new ChangeEventsCommand(getId().untyped,
308  tr("Delete Region"));
309  Event e = m_events.getEventByIndex(row);
310  command->remove(e);
311  return command->finish();
312  }
313 
314 
318  void toXml(QTextStream &out,
319  QString indent = "",
320  QString extraAttributes = "") const override {
321 
323  (out,
324  indent,
325  QString("type=\"sparse\" dimensions=\"3\" resolution=\"%1\" "
326  "notifyOnAdd=\"%2\" dataset=\"%3\" subtype=\"%4\" "
327  "valueQuantization=\"%5\" minimum=\"%6\" maximum=\"%7\" "
328  "units=\"%8\" %9")
329  .arg(m_resolution)
330  .arg("true") // always true after model reaches 100% -
331  // subsequent events are always notified
332  .arg(m_events.getExportId())
333  .arg("region")
334  .arg(m_valueQuantization)
335  .arg(m_valueMinimum)
336  .arg(m_valueMaximum)
337  .arg(encodeEntities(m_units))
338  .arg(extraAttributes));
339 
340  m_events.toXml(out, indent, QString("dimensions=\"3\""));
341  }
342 
343  QVector<QString>
344  getStringExportHeaders(DataExportOptions options) const override {
345  return m_events.getStringExportHeaders(options, {});
346  }
347 
348  QVector<QVector<QString>>
350  sv_frame_t startFrame,
351  sv_frame_t duration) const override {
353  (options,
354  startFrame,
355  duration,
356  m_sampleRate,
357  m_resolution,
358  Event().withValue(0.f).withDuration(m_resolution));
359  }
360 
361 protected:
364 
365  std::atomic<float> m_valueMinimum;
366  std::atomic<float> m_valueMaximum;
367  std::atomic<bool> m_haveExtents;
370  QString m_units;
372  std::atomic<int> m_completion;
373 
375 };
376 
377 #endif
QString getTypeName() const override
Return the type of the model.
Definition: RegionModel.h:79
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
int getResolution() const
Definition: RegionModel.h:94
QVector< QVector< QString > > toStringExportRows(DataExportOptions options, 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: RegionModel.h:349
bool contains(const Event &e) const
bool getNearestEventMatching(sv_frame_t startSearchAt, std::function< bool(Event)> predicate, EventSeries::Direction direction, Event &found) const
Definition: RegionModel.h:161
float getValue() const
Definition: Event.h:122
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: RegionModel.h:219
int count() const
Definition: EventSeries.cpp:79
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
bool haveDistinctValues() const
Definition: RegionModel.h:105
EventVector getEventsCovering(sv_frame_t f) const
Definition: RegionModel.h:149
QString getScaleUnits() const
Definition: RegionModel.h:96
void add(const Event &e)
Definition: EventSeries.cpp:89
void registerUnit(QString unit)
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
bool isEmpty() const
Definition: RegionModel.h:137
sv_frame_t getFrameForRow(int row) const override
Return the frame time for the given row.
Definition: RegionModel.h:225
Event getEventByIndex(int index) const
Return the event at the given numerical index in the series, where 0 = the first event and count()-1 ...
int getColumnCount() const override
Return the number of columns (values/labels/etc per item).
Definition: RegionModel.h:215
void update(sv_frame_t frame, sv_frame_t duration)
EventVector getAllEvents() const
Retrieve all events, in their natural order.
EventVector getEventsSpanning(sv_frame_t f, sv_frame_t duration) const
Definition: RegionModel.h:146
#define ISNAN
Definition: System.h:103
EventVector getAllEvents() const
Definition: RegionModel.h:143
int m_resolution
Definition: RegionModel.h:363
sv_frame_t getStartFrame() const
Return the frame of the first event in the series.
QVector< QVector< QString > > toStringExportRows(DataExportOptions options, sv_frame_t startFrame, sv_frame_t duration, sv_samplerate_t sampleRate, sv_frame_t resolution, Event fillEvent) const
Emit events starting within the given range as string rows ready for conversion to an e...
Command * getRemoveRowCommand(int row) override
Return a command to delete the row with the given index.
Definition: RegionModel.h:305
void add(Event e) override
Editing methods.
Definition: RegionModel.h:172
RegionModel(sv_samplerate_t sampleRate, int resolution, bool notifyOnAdd=true)
Definition: RegionModel.h:40
virtual ~RegionModel()
Definition: RegionModel.h:76
Command * getInsertRowCommand(int row) override
Return a command to insert a new row before the row with the given index.
Definition: RegionModel.h:296
int getEventCount() const
Query methods.
Definition: RegionModel.h:134
void makeDeferredNotifications()
QVector< QString > getStringExportHeaders(DataExportOptions options, Event::ExportNameOptions) const
Return a label for each column that would be written by toStringExportRows.
void setCompletion(int completion, bool update=true)
Definition: RegionModel.h:112
bool m_haveDistinctValues
Definition: RegionModel.h:369
SortType getSortType(int column) const override
Return the sort type (numeric or alphabetical) for the column.
Definition: RegionModel.h:248
Id getId() const
Return an id for this object.
Definition: ById.h:193
void setValueQuantization(float q)
Definition: RegionModel.h:103
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...
bool hasValue() const
Definition: Event.h:121
Event withLabel(QString label) const
Definition: Event.h:160
void toXml(QTextStream &out, QString indent, QString extraAttributes) const override
Emit to XML as a dataset element.
static QString encodeEntities(QString)
int getCompletion() const override
Return an estimated percentage value showing how far through any background operation used to calcula...
Definition: RegionModel.h:110
sv_frame_t getDuration() const
Definition: Event.h:138
float getValueQuantization() const
Definition: RegionModel.h:102
bool isEmpty() const
Definition: EventSeries.cpp:72
EventVector getEventsCovering(sv_frame_t frame) const
Retrieve all events that cover the given frame.
QString getHeading(int column) const override
Return the heading for a given column, e.g.
Definition: RegionModel.h:237
QVariant getData(int row, int column, int role) const override
Get the value in the given cell, for the given role.
Definition: RegionModel.h:253
int getRowCount() const override
TabularModel methods.
Definition: RegionModel.h:211
static QVariant adaptValueForRole(float value, QString unit, int role)
Definition: TabularModel.h:133
bool containsEvent(const Event &e) const
Definition: RegionModel.h:140
static UnitDatabase * getInstance()
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
void toXml(QTextStream &out, QString indent="", QString extraAttributes="") const override
XmlExportable methods.
Definition: RegionModel.h:318
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
bool isSparse() const override
Return true if this is a sparse model.
Definition: RegionModel.h:80
void completionChanged(ModelId myId)
Emitted when some internal processing has advanced a stage, but the model has not changed externally...
EventSeries m_events
Definition: RegionModel.h:374
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)
sv_samplerate_t m_sampleRate
Definition: RegionModel.h:362
EventVector getEventsWithin(sv_frame_t f, sv_frame_t duration) const
Definition: RegionModel.h:152
ExportId getExportId() const
Return the numerical export identifier for this object.
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...
RegionModel(sv_samplerate_t sampleRate, int resolution, float valueMinimum, float valueMaximum, bool notifyOnAdd=true)
Definition: RegionModel.h:58
RegionModel – a model for intervals associated with a value, which we call regions for no very compe...
Definition: RegionModel.h:33
bool isOK() const override
Return true if the model was constructed successfully.
Definition: RegionModel.h:81
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...
void setScaleUnits(QString units)
Definition: RegionModel.h:97
#define ISINF
Definition: System.h:104
An immutable(-ish) type used for point and event representation in sparse models, as well as for inte...
Definition: Event.h:55
float getValueMinimum() const
Definition: RegionModel.h:107
DeferredNotifier m_notifier
Definition: RegionModel.h:371
std::atomic< float > m_valueMaximum
Definition: RegionModel.h:366
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
EventVector getEventsStartingWithin(sv_frame_t f, sv_frame_t duration) const
Definition: RegionModel.h:155
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: RegionModel.h:233
void switchMode(Mode newMode)
sv_samplerate_t getSampleRate() const override
Return the frame rate in frames per second.
Definition: RegionModel.h:93
QVector< QString > getStringExportHeaders(DataExportOptions options) const override
Return a label for each column that would be written by toStringExportRows.
Definition: RegionModel.h:344
std::vector< Event > EventVector
Definition: Event.h:494
std::atomic< int > m_completion
Definition: RegionModel.h:372
Interface for classes that can be modified through these commands.
Definition: EventCommands.h:26
QString getLabel() const
Definition: Event.h:158
std::atomic< bool > m_haveExtents
Definition: RegionModel.h:367
float getValueMaximum() const
Definition: RegionModel.h:108
EventVector getEventsStartingAt(sv_frame_t f) const
Definition: RegionModel.h:158
sv_frame_t getStartFrame() const override
Return the first audio frame spanned by the model.
Definition: RegionModel.h:83
QString m_units
Definition: RegionModel.h:370
float m_valueQuantization
Definition: RegionModel.h:368
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...
void modelChanged(ModelId myId)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
Command to add or remove a series of events to or from an editable, with undo.
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: RegionModel.h:273
sv_frame_t getTrueEndFrame() const override
Return the audio frame at the end of the model.
Definition: RegionModel.h:86
bool isEditable() const override
Return true if the model is user-editable, false otherwise.
Definition: RegionModel.h:271
std::atomic< float > m_valueMinimum
Definition: RegionModel.h:365
int DataExportOptions