SparseTimeValueModel.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_SPARSE_TIME_VALUE_MODEL_H
16 #define SV_SPARSE_TIME_VALUE_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"
27 
28 #include "system/System.h"
29 
34 class SparseTimeValueModel : public Model,
35  public TabularModel,
36  public EventEditable
37 {
38  Q_OBJECT
39 
40 public:
42  int resolution,
43  bool notifyOnAdd = true) :
44  m_sampleRate(sampleRate),
45  m_resolution(resolution),
46  m_valueMinimum(0.f),
47  m_valueMaximum(0.f),
48  m_haveExtents(false),
49  m_haveTextLabels(false),
50  m_notifier(this,
51  getId(),
52  notifyOnAdd ?
53  DeferredNotifier::NOTIFY_ALWAYS :
54  DeferredNotifier::NOTIFY_DEFERRED),
55  m_completion(100) {
56  // Model is playable, but may not sound (if units not Hz or
57  // range unsuitable)
59  (getId().untyped, this);
60  }
61 
62  SparseTimeValueModel(sv_samplerate_t sampleRate, int resolution,
63  float valueMinimum, float valueMaximum,
64  bool notifyOnAdd = true) :
65  m_sampleRate(sampleRate),
66  m_resolution(resolution),
67  m_valueMinimum(valueMinimum),
68  m_valueMaximum(valueMaximum),
69  m_haveExtents(true),
70  m_haveTextLabels(false),
71  m_notifier(this,
72  getId(),
73  notifyOnAdd ?
74  DeferredNotifier::NOTIFY_ALWAYS :
75  DeferredNotifier::NOTIFY_DEFERRED),
76  m_completion(100) {
77  // Model is playable, but may not sound (if units not Hz or
78  // range unsuitable)
80  (getId().untyped, this);
81  }
82 
85  (getId().untyped);
86  }
87 
88  QString getTypeName() const override { return tr("Sparse Time-Value"); }
89  bool isSparse() const override { return true; }
90  bool isOK() const override { return true; }
91 
92  sv_frame_t getStartFrame() const override {
93  return m_events.getStartFrame();
94  }
95  sv_frame_t getTrueEndFrame() const override {
96  if (m_events.isEmpty()) return 0;
98  if (e % m_resolution == 0) return e;
99  else return (e / m_resolution + 1) * m_resolution;
100  }
101 
102  sv_samplerate_t getSampleRate() const override { return m_sampleRate; }
103  int getResolution() const { return m_resolution; }
104 
105  bool canPlay() const override { return true; }
106  bool getDefaultPlayAudible() const override { return false; } // user must unmute
107 
108  QString getScaleUnits() const {
109  QMutexLocker locker(&m_mutex);
110  return m_units;
111  }
112  void setScaleUnits(QString units) {
113  QMutexLocker locker(&m_mutex);
114  m_units = units;
116  }
117 
118  bool hasTextLabels() const { return m_haveTextLabels; }
119 
120  float getValueMinimum() const { return m_valueMinimum; }
121  float getValueMaximum() const { return m_valueMaximum; }
122 
123  int getCompletion() const override { return m_completion; }
124 
125  void setCompletion(int completion, bool update = true) {
126 
127  {
128  if (m_completion == completion) return;
129  m_completion = completion;
130  }
131 
132  if (update) {
134  }
135 
136  emit completionChanged(getId());
137 
138  if (completion == 100) {
139  // henceforth:
141  emit modelChanged(getId());
142  }
143  }
144 
149  int getEventCount() const {
150  return m_events.count();
151  }
152  bool isEmpty() const {
153  return m_events.isEmpty();
154  }
155  bool containsEvent(const Event &e) const {
156  return m_events.contains(e);
157  }
159  return m_events.getAllEvents();
160  }
162  return m_events.getEventsSpanning(f, duration);
163  }
165  return m_events.getEventsCovering(f);
166  }
168  int overspill = 0) const {
169  return m_events.getEventsWithin(f, duration, overspill);
170  }
172  return m_events.getEventsStartingWithin(f, duration);
173  }
175  return m_events.getEventsStartingAt(f);
176  }
178  std::function<bool(Event)> predicate,
179  EventSeries::Direction direction,
180  Event &found) const {
182  (startSearchAt, predicate, direction, found);
183  }
184 
188  void add(Event e) override {
189 
190  bool allChange = false;
191 
192  m_events.add(e.withoutDuration()); // can't have duration here
193 
194  if (e.getLabel() != "") {
195  m_haveTextLabels = true;
196  }
197 
198  float v = e.getValue();
199  if (!ISNAN(v) && !ISINF(v)) {
200  if (!m_haveExtents || v < m_valueMinimum) {
201  m_valueMinimum = v; allChange = true;
202  }
203  if (!m_haveExtents || v > m_valueMaximum) {
204  m_valueMaximum = v; allChange = true;
205  }
206  m_haveExtents = true;
207  }
208 
210 
211  if (allChange) {
212  emit modelChanged(getId());
213  }
214  }
215 
216  void remove(Event e) override {
217  m_events.remove(e);
218  emit modelChangedWithin(getId(),
219  e.getFrame(), e.getFrame() + m_resolution);
220  }
221 
226  int getRowCount() const override {
227  return m_events.count();
228  }
229 
230  int getColumnCount() const override {
231  return 4;
232  }
233 
234  bool isColumnTimeValue(int column) const override {
235  return (column < 2);
236  }
237 
238  sv_frame_t getFrameForRow(int row) const override {
239  if (row < 0 || row >= m_events.count()) {
240  return 0;
241  }
242  Event e = m_events.getEventByIndex(row);
243  return e.getFrame();
244  }
245 
246  int getRowForFrame(sv_frame_t frame) const override {
247  return m_events.getIndexForEvent(Event(frame));
248  }
249 
250  QString getHeading(int column) const override {
251  switch (column) {
252  case 0: return tr("Time");
253  case 1: return tr("Frame");
254  case 2: return tr("Value");
255  case 3: return tr("Label");
256  default: return tr("Unknown");
257  }
258  }
259 
260  SortType getSortType(int column) const override {
261  if (column == 3) return SortAlphabetical;
262  return SortNumeric;
263  }
264 
265  QVariant getData(int row, int column, int role) const override {
266 
267  if (row < 0 || row >= m_events.count()) {
268  return QVariant();
269  }
270 
271  Event e = m_events.getEventByIndex(row);
272 
273  switch (column) {
274  case 0: return adaptFrameForRole(e.getFrame(), getSampleRate(), role);
275  case 1: return int(e.getFrame());
276  case 2: return adaptValueForRole(e.getValue(), getScaleUnits(), role);
277  case 3: return e.getLabel();
278  default: return QVariant();
279  }
280  }
281 
282  bool isEditable() const override { return true; }
283 
284  Command *getSetDataCommand(int row, int column, const QVariant &value,
285  int role) override {
286  if (row < 0 || row >= m_events.count()) return nullptr;
287  if (role != Qt::EditRole) return nullptr;
288 
289  Event e0 = m_events.getEventByIndex(row);
290  Event e1;
291 
292  switch (column) {
293  case 0: e1 = e0.withFrame(sv_frame_t(round(value.toDouble() *
294  getSampleRate()))); break;
295  case 1: e1 = e0.withFrame(value.toInt()); break;
296  case 2: e1 = e0.withValue(float(value.toDouble())); break;
297  case 3: e1 = e0.withLabel(value.toString()); break;
298  }
299 
300  auto command = new ChangeEventsCommand(getId().untyped, tr("Edit Data"));
301  command->remove(e0);
302  command->add(e1);
303  return command->finish();
304  }
305 
306  Command *getInsertRowCommand(int row) override {
307  if (row < 0 || row >= m_events.count()) return nullptr;
308  auto command = new ChangeEventsCommand(getId().untyped,
309  tr("Add Point"));
310  Event e = m_events.getEventByIndex(row);
311  command->add(e);
312  return command->finish();
313  }
314 
315  Command *getRemoveRowCommand(int row) override {
316  if (row < 0 || row >= m_events.count()) return nullptr;
317  auto command = new ChangeEventsCommand(getId().untyped,
318  tr("Delete Point"));
319  Event e = m_events.getEventByIndex(row);
320  command->remove(e);
321  return command->finish();
322  }
323 
327  void toXml(QTextStream &out,
328  QString indent = "",
329  QString extraAttributes = "") const override {
330 
332  (out,
333  indent,
334  QString("type=\"sparse\" dimensions=\"2\" resolution=\"%1\" "
335  "notifyOnAdd=\"%2\" dataset=\"%3\" "
336  "minimum=\"%4\" maximum=\"%5\" "
337  "units=\"%6\" %7")
338  .arg(m_resolution)
339  .arg("true") // always true after model reaches 100% -
340  // subsequent events are always notified
341  .arg(m_events.getExportId())
342  .arg(m_valueMinimum)
343  .arg(m_valueMaximum)
344  .arg(encodeEntities(m_units))
345  .arg(extraAttributes));
346 
347  m_events.toXml(out, indent, QString("dimensions=\"2\""));
348  }
349 
350  QVector<QString>
351  getStringExportHeaders(DataExportOptions options) const override {
352  return m_events.getStringExportHeaders(options, {});
353  }
354 
355  QVector<QVector<QString>>
357  sv_frame_t startFrame,
358  sv_frame_t duration) const override {
359  return m_events.toStringExportRows(options,
360  startFrame,
361  duration,
362  m_sampleRate,
363  m_resolution,
364  Event().withValue(0.f));
365  }
366 
367 protected:
370 
371  std::atomic<float> m_valueMinimum;
372  std::atomic<float> m_valueMaximum;
373  std::atomic<bool> m_haveExtents;
374  std::atomic<bool> m_haveTextLabels;
375  QString m_units;
377  std::atomic<int> m_completion;
378 
380 };
381 
382 #endif
383 
384 
385 
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
std::atomic< bool > m_haveExtents
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
static PlayParameterRepository * getInstance()
Command * getRemoveRowCommand(int row) override
Return a command to delete the row with the given index.
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...
bool contains(const Event &e) const
float getValue() const
Definition: Event.h:122
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...
int count() const
Definition: EventSeries.cpp:79
EventVector getEventsCovering(sv_frame_t f) const
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
bool getNearestEventMatching(sv_frame_t startSearchAt, std::function< bool(Event)> predicate, EventSeries::Direction direction, Event &found) const
sv_samplerate_t getSampleRate() const override
Return the frame rate in frames per second.
QVariant getData(int row, int column, int role) const override
Get the value in the given cell, for the given role.
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
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...
static QVariant adaptFrameForRole(sv_frame_t frame, sv_samplerate_t rate, int role)
Definition: TabularModel.h:124
void setCompletion(int completion, bool update=true)
QString getTypeName() const override
Return the type of the model.
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.
std::atomic< float > m_valueMaximum
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.
int getRowCount() const override
TabularModel methods.
#define ISNAN
Definition: System.h:103
void add(Event e) override
Editing methods.
bool isSparse() const override
Return true if this is a sparse model.
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...
int getEventCount() const
Query methods.
void toXml(QTextStream &out, QString indent="", QString extraAttributes="") const override
XmlExportable methods.
float getValueMaximum() const
void makeDeferredNotifications()
std::atomic< bool > m_haveTextLabels
QVector< QString > getStringExportHeaders(DataExportOptions options, Event::ExportNameOptions) const
Return a label for each column that would be written by toStringExportRows.
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 getHeading(int column) const override
Return the heading for a given column, e.g.
SortType getSortType(int column) const override
Return the sort type (numeric or alphabetical) for the column.
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)
EventVector getEventsStartingWithin(sv_frame_t f, sv_frame_t duration) const
float getValueMinimum() const
bool isEmpty() const
Definition: EventSeries.cpp:72
bool getDefaultPlayAudible() const override
DeferredNotifier m_notifier
EventVector getEventsCovering(sv_frame_t frame) const
Retrieve all events that cover the given frame.
EventVector getAllEvents() const
EventVector getEventsStartingAt(sv_frame_t f) const
static QVariant adaptValueForRole(float value, QString unit, int role)
Definition: TabularModel.h:133
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...
SparseTimeValueModel(sv_samplerate_t sampleRate, int resolution, float valueMinimum, float valueMaximum, bool notifyOnAdd=true)
QVector< QString > getStringExportHeaders(DataExportOptions options) const override
Return a label for each column that would be written by toStringExportRows.
std::atomic< int > m_completion
std::atomic< float > m_valueMinimum
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...
Event withoutDuration() const
Definition: Event.h:150
QMutex m_mutex
Definition: Model.h:337
bool isEditable() const override
Return true if the model is user-editable, false otherwise.
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.
void removePlayable(int id)
Unregister a playable.
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.
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...
sv_frame_t getStartFrame() const override
Return the first audio frame spanned by the model.
A model representing a wiggly-line plot with points at arbitrary intervals of the model resolution...
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...
sv_frame_t getTrueEndFrame() const override
Return the audio frame at the end of the model.
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...
#define ISINF
Definition: System.h:104
bool containsEvent(const Event &e) const
An immutable(-ish) type used for point and event representation in sparse models, as well as for inte...
Definition: Event.h:55
EventVector getEventsWithin(sv_frame_t f, sv_frame_t duration, int overspill=0) const
QString getScaleUnits() const
void addPlayable(int id, const Playable *)
Register a playable.
SparseTimeValueModel(sv_samplerate_t sampleRate, int resolution, bool notifyOnAdd=true)
void setScaleUnits(QString units)
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
sv_frame_t getFrameForRow(int row) const override
Return the frame time for the given row.
sv_samplerate_t m_sampleRate
void switchMode(Mode newMode)
int getCompletion() const override
Return an estimated percentage value showing how far through any background operation used to calcula...
std::vector< Event > EventVector
Definition: Event.h:494
Interface for classes that can be modified through these commands.
Definition: EventCommands.h:26
QString getLabel() const
Definition: Event.h:158
int getColumnCount() const override
Return the number of columns (values/labels/etc per item).
EventVector getEventsSpanning(sv_frame_t f, sv_frame_t duration) const
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 * getInsertRowCommand(int row) override
Return a command to insert a new row before the row with the given index.
Command to add or remove a series of events to or from an editable, with undo.
bool canPlay() const override
int DataExportOptions
bool isOK() const override
Return true if the model was constructed successfully.