Mercurial > hg > svcore
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 |