comparison data/model/NoteModel.h @ 1798:13bd41bd8a17

Some work on making Model classes thread-safe in typical use - and documenting this. Some of the implementations are simpler now that EventSeries is thread-safe
author Chris Cannam
date Tue, 01 Oct 2019 11:22:48 +0100
parents 6d09d68165a4
children 343ef2a866a4
comparison
equal deleted inserted replaced
1797:e8b552549225 1798:13bd41bd8a17
26 #include "base/RealTime.h" 26 #include "base/RealTime.h"
27 #include "base/PlayParameterRepository.h" 27 #include "base/PlayParameterRepository.h"
28 #include "base/Pitch.h" 28 #include "base/Pitch.h"
29 #include "system/System.h" 29 #include "system/System.h"
30 30
31 #include <QMutex>
32 #include <QMutexLocker> 31 #include <QMutexLocker>
33 32
34 class NoteModel : public Model, 33 class NoteModel : public Model,
35 public TabularModel, 34 public TabularModel,
36 public NoteExportable, 35 public NoteExportable,
54 m_valueMinimum(0.f), 53 m_valueMinimum(0.f),
55 m_valueMaximum(0.f), 54 m_valueMaximum(0.f),
56 m_haveExtents(false), 55 m_haveExtents(false),
57 m_valueQuantization(0), 56 m_valueQuantization(0),
58 m_units(""), 57 m_units(""),
59 m_extendTo(0),
60 m_notifier(this, 58 m_notifier(this,
61 getId(), 59 getId(),
62 notifyOnAdd ? 60 notifyOnAdd ?
63 DeferredNotifier::NOTIFY_ALWAYS : 61 DeferredNotifier::NOTIFY_ALWAYS :
64 DeferredNotifier::NOTIFY_DEFERRED), 62 DeferredNotifier::NOTIFY_DEFERRED),
81 m_valueMinimum(valueMinimum), 79 m_valueMinimum(valueMinimum),
82 m_valueMaximum(valueMaximum), 80 m_valueMaximum(valueMaximum),
83 m_haveExtents(true), 81 m_haveExtents(true),
84 m_valueQuantization(0), 82 m_valueQuantization(0),
85 m_units(""), 83 m_units(""),
86 m_extendTo(0),
87 m_notifier(this, 84 m_notifier(this,
88 getId(), 85 getId(),
89 notifyOnAdd ? 86 notifyOnAdd ?
90 DeferredNotifier::NOTIFY_ALWAYS : 87 DeferredNotifier::NOTIFY_ALWAYS :
91 DeferredNotifier::NOTIFY_DEFERRED), 88 DeferredNotifier::NOTIFY_DEFERRED),
103 Subtype getSubtype() const { return m_subtype; } 100 Subtype getSubtype() const { return m_subtype; }
104 bool isSparse() const override { return true; } 101 bool isSparse() const override { return true; }
105 bool isOK() const override { return true; } 102 bool isOK() const override { return true; }
106 103
107 sv_frame_t getStartFrame() const override { 104 sv_frame_t getStartFrame() const override {
105 QMutexLocker locker(&m_mutex);
108 return m_events.getStartFrame(); 106 return m_events.getStartFrame();
109 } 107 }
110 sv_frame_t getTrueEndFrame() const override { 108 sv_frame_t getTrueEndFrame() const override {
109 QMutexLocker locker(&m_mutex);
111 if (m_events.isEmpty()) return 0; 110 if (m_events.isEmpty()) return 0;
112 sv_frame_t e = m_events.getEndFrame(); 111 sv_frame_t e = m_events.getEndFrame();
113 if (e % m_resolution == 0) return e; 112 if (e % m_resolution == 0) return e;
114 else return (e / m_resolution + 1) * m_resolution; 113 else return (e / m_resolution + 1) * m_resolution;
115 } 114 }
120 bool canPlay() const override { return true; } 119 bool canPlay() const override { return true; }
121 QString getDefaultPlayClipId() const override { 120 QString getDefaultPlayClipId() const override {
122 return "elecpiano"; 121 return "elecpiano";
123 } 122 }
124 123
125 QString getScaleUnits() const { return m_units; } 124 QString getScaleUnits() const {
125 QMutexLocker locker(&m_mutex);
126 return m_units;
127 }
126 void setScaleUnits(QString units) { 128 void setScaleUnits(QString units) {
129 QMutexLocker locker(&m_mutex);
127 m_units = units; 130 m_units = units;
128 UnitDatabase::getInstance()->registerUnit(units); 131 UnitDatabase::getInstance()->registerUnit(units);
129 } 132 }
130 133
131 float getValueQuantization() const { return m_valueQuantization; } 134 float getValueQuantization() const { return m_valueQuantization; }
136 139
137 int getCompletion() const override { return m_completion; } 140 int getCompletion() const override { return m_completion; }
138 141
139 void setCompletion(int completion, bool update = true) { 142 void setCompletion(int completion, bool update = true) {
140 143
141 { QMutexLocker locker(&m_mutex); 144 {
142 if (m_completion == completion) return; 145 if (m_completion == completion) return;
143 m_completion = completion; 146 m_completion = completion;
144 } 147 }
145 148
146 if (update) { 149 if (update) {
200 */ 203 */
201 void add(Event e) override { 204 void add(Event e) override {
202 205
203 bool allChange = false; 206 bool allChange = false;
204 207
205 { 208 m_events.add(e);
206 QMutexLocker locker(&m_mutex); 209 float v = e.getValue();
207 m_events.add(e); 210 if (!ISNAN(v) && !ISINF(v)) {
208 211 if (!m_haveExtents || v < m_valueMinimum) {
209 float v = e.getValue(); 212 m_valueMinimum = v; allChange = true;
210 if (!ISNAN(v) && !ISINF(v)) {
211 if (!m_haveExtents || v < m_valueMinimum) {
212 m_valueMinimum = v; allChange = true;
213 }
214 if (!m_haveExtents || v > m_valueMaximum) {
215 m_valueMaximum = v; allChange = true;
216 }
217 m_haveExtents = true;
218 } 213 }
214 if (!m_haveExtents || v > m_valueMaximum) {
215 m_valueMaximum = v; allChange = true;
216 }
217 m_haveExtents = true;
219 } 218 }
220 219
221 m_notifier.update(e.getFrame(), e.getDuration() + m_resolution); 220 m_notifier.update(e.getFrame(), e.getDuration() + m_resolution);
222 221
223 if (allChange) { 222 if (allChange) {
224 emit modelChanged(getId()); 223 emit modelChanged(getId());
225 } 224 }
226 } 225 }
227 226
228 void remove(Event e) override { 227 void remove(Event e) override {
229 { 228 m_events.remove(e);
230 QMutexLocker locker(&m_mutex);
231 m_events.remove(e);
232 }
233 emit modelChangedWithin(getId(), 229 emit modelChangedWithin(getId(),
234 e.getFrame(), 230 e.getFrame(),
235 e.getFrame() + e.getDuration() + m_resolution); 231 e.getFrame() + e.getDuration() + m_resolution);
236 } 232 }
237 233
406 protected: 402 protected:
407 Subtype m_subtype; 403 Subtype m_subtype;
408 sv_samplerate_t m_sampleRate; 404 sv_samplerate_t m_sampleRate;
409 int m_resolution; 405 int m_resolution;
410 406
411 float m_valueMinimum; 407 std::atomic<float> m_valueMinimum;
412 float m_valueMaximum; 408 std::atomic<float> m_valueMaximum;
413 bool m_haveExtents; 409 std::atomic<bool> m_haveExtents;
414 float m_valueQuantization; 410 float m_valueQuantization;
415 QString m_units; 411 QString m_units;
416 sv_frame_t m_extendTo;
417 DeferredNotifier m_notifier; 412 DeferredNotifier m_notifier;
418 int m_completion; 413 std::atomic<int> m_completion;
419 414
420 EventSeries m_events; 415 EventSeries m_events;
421
422 mutable QMutex m_mutex;
423
424 //!!! do we have general docs for ownership and synchronisation of models?
425 // this might be a good opportunity to stop using bare pointers to them
426 }; 416 };
427 417
428 #endif 418 #endif