comparison data/model/NoteModel.h @ 1644:513192aa9b03 single-point

Further API updates
author Chris Cannam
date Wed, 13 Mar 2019 16:00:13 +0000
parents 7a23dfe65d66
children b429750e64a8
comparison
equal deleted inserted replaced
1643:7a23dfe65d66 1644:513192aa9b03
35 public NoteExportable 35 public NoteExportable
36 { 36 {
37 Q_OBJECT 37 Q_OBJECT
38 38
39 public: 39 public:
40 NoteModel(sv_samplerate_t sampleRate, int resolution, 40 NoteModel(sv_samplerate_t sampleRate,
41 int resolution,
41 bool notifyOnAdd = true) : 42 bool notifyOnAdd = true) :
42 m_sampleRate(sampleRate), 43 m_sampleRate(sampleRate),
43 m_resolution(resolution), 44 m_resolution(resolution),
44 m_valueMinimum(0.f), 45 m_valueMinimum(0.f),
45 m_valueMaximum(0.f), 46 m_valueMaximum(0.f),
80 81
81 bool isOK() const override { return true; } 82 bool isOK() const override { return true; }
82 sv_frame_t getStartFrame() const override { return m_events.getStartFrame(); } 83 sv_frame_t getStartFrame() const override { return m_events.getStartFrame(); }
83 sv_frame_t getEndFrame() const override { return m_events.getEndFrame(); } 84 sv_frame_t getEndFrame() const override { return m_events.getEndFrame(); }
84 sv_samplerate_t getSampleRate() const override { return m_sampleRate; } 85 sv_samplerate_t getSampleRate() const override { return m_sampleRate; }
86 int getResolution() const { return m_resolution; }
85 87
86 bool canPlay() const override { return true; } 88 bool canPlay() const override { return true; }
87 QString getDefaultPlayClipId() const override { 89 QString getDefaultPlayClipId() const override {
88 return "elecpiano"; 90 return "elecpiano";
89 } 91 }
143 if (emitRegionChanged) { 145 if (emitRegionChanged) {
144 emit modelChangedWithin(m_sinceLastNotifyMin, m_sinceLastNotifyMax); 146 emit modelChangedWithin(m_sinceLastNotifyMin, m_sinceLastNotifyMax);
145 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1; 147 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
146 } 148 }
147 } 149 }
150
151 /**
152 * Query methods.
153 */
154
155 int getEventCount() const {
156 return m_events.count();
157 }
158 bool isEmpty() const {
159 return m_events.isEmpty();
160 }
161 bool containsEvent(const Event &e) const {
162 return m_events.contains(e);
163 }
164 EventVector getAllEvents() const {
165 return m_events.getAllEvents();
166 }
167 EventVector getEventsSpanning(sv_frame_t f, sv_frame_t duration) const {
168 return m_events.getEventsSpanning(f, duration);
169 }
170 EventVector getEventsWithin(sv_frame_t f, sv_frame_t duration) const {
171 return m_events.getEventsWithin(f, duration);
172 }
173 EventVector getEventsStartingWithin(sv_frame_t f, sv_frame_t duration) const {
174 return m_events.getEventsStartingWithin(f, duration);
175 }
176 EventVector getEventsCovering(sv_frame_t f) const {
177 return m_events.getEventsCovering(f);
178 }
179
180 /**
181 * Editing commands and methods.
182 */
183
184 class EditCommand : public Command
185 {
186 public:
187 //!!! borrowed ptr
188 EditCommand(NoteModel *model, QString name) :
189 m_model(model), m_name(name) { }
190
191 QString getName() const override {
192 return m_name;
193 }
194
195 void add(Event e) {
196 m_add.insert(e);
197 }
198
199 void remove(Event e) {
200 m_remove.insert(e);
201 }
202
203 void execute() override {
204 for (const Event &e: m_add) m_model->add(e);
205 for (const Event &e: m_remove) m_model->remove(e);
206 }
207
208 void unexecute() override {
209 for (const Event &e: m_remove) m_model->add(e);
210 for (const Event &e: m_add) m_model->remove(e);
211 }
212
213 EditCommand *finish() {
214 if (m_add.empty() && m_remove.empty()) {
215 delete this;
216 return nullptr;
217 } else {
218 return this;
219 }
220 }
221
222 private:
223 NoteModel *m_model;
224 std::set<Event> m_add;
225 std::set<Event> m_remove;
226 QString m_name;
227 };
228
229 void add(Event e) {
230
231 bool allChange = false;
232
233 {
234 QMutexLocker locker(&m_mutex);
235 m_events.add(e);
236 //!!!??? if (point.getLabel() != "") m_hasTextLabels = true;
237
238 float v = e.getValue();
239 if (!ISNAN(v) && !ISINF(v)) {
240 if (!m_haveExtents || v < m_valueMinimum) {
241 m_valueMinimum = v; allChange = true;
242 }
243 if (!m_haveExtents || v > m_valueMaximum) {
244 m_valueMaximum = v; allChange = true;
245 }
246 m_haveExtents = true;
247 }
248
249 sv_frame_t f = e.getFrame();
250
251 if (!m_notifyOnAdd) {
252 if (m_sinceLastNotifyMin == -1 || f < m_sinceLastNotifyMin) {
253 m_sinceLastNotifyMin = f;
254 }
255 if (m_sinceLastNotifyMax == -1 || f > m_sinceLastNotifyMax) {
256 m_sinceLastNotifyMax = f;
257 }
258 }
259 }
260
261 if (m_notifyOnAdd) {
262 emit modelChangedWithin(e.getFrame(),
263 e.getFrame() + e.getDuration() + m_resolution);
264 }
265 if (allChange) {
266 emit modelChanged();
267 }
268 }
269
270 void remove(Event e) {
271 {
272 QMutexLocker locker(&m_mutex);
273 m_events.remove(e);
274 }
275 emit modelChangedWithin(e.getFrame(),
276 e.getFrame() + e.getDuration() + m_resolution);
277 }
278
279 /**
280 * TabularModel methods.
281 */
282
283 int getRowCount() const override {
284 return m_events.count();
285 }
286
287 int getColumnCount() const override {
288 return 6;
289 }
290
291 bool isColumnTimeValue(int column) const override {
292 // NB duration is not a "time value" -- that's for columns
293 // whose sort ordering is exactly that of the frame time
294 return (column < 2);
295 }
296
297 sv_frame_t getFrameForRow(int row) const override {
298 if (row < 0 || row >= m_events.count()) {
299 return 0;
300 }
301 Event e = m_events.getEventByIndex(row);
302 return e.getFrame();
303 }
304
305 int getRowForFrame(sv_frame_t frame) const override {
306 return m_events.getIndexForEvent(Event(frame));
307 }
308
309 QString getHeading(int column) const override {
310 switch (column) {
311 case 0: return tr("Time");
312 case 1: return tr("Frame");
313 case 2: return tr("Pitch");
314 case 3: return tr("Duration");
315 case 4: return tr("Level");
316 case 5: return tr("Label");
317 default: return tr("Unknown");
318 }
319 }
320
321 QVariant getData(int row, int column, int role) const override {
322
323 if (row < 0 || row >= m_events.count()) {
324 return QVariant();
325 }
326
327 Event e = m_events.getEventByIndex(row);
328
329 switch (column) {
330 case 0: return adaptFrameForRole(e.getFrame(), getSampleRate(), role);
331 case 1: return int(e.getFrame());
332 case 2: return adaptValueForRole(e.getValue(), getScaleUnits(), role);
333 case 3: return int(e.getDuration());
334 case 4: return e.getLevel();
335 case 5: return e.getLabel();
336 default: return QVariant();
337 }
338 }
339
340 Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override
341 {
342 if (row < 0 || row >= m_events.count()) return nullptr;
343 if (role != Qt::EditRole) return nullptr;
344
345 Event e0 = m_events.getEventByIndex(row);
346 Event e1;
347
348 switch (column) {
349 case 0: e1 = e0.withFrame(sv_frame_t(round(value.toDouble() *
350 getSampleRate()))); break;
351 case 1: e1 = e0.withFrame(value.toInt()); break;
352 case 2: e1 = e0.withValue(float(value.toDouble())); break;
353 case 3: e1 = e0.withDuration(value.toInt()); break;
354 case 4: e1 = e0.withLevel(float(value.toDouble())); break;
355 case 5: e1 = e0.withLabel(value.toString()); break;
356 }
357
358 EditCommand *command = new EditCommand(this, tr("Edit Data"));
359 command->remove(e0);
360 command->add(e1);
361 return command->finish();
362 }
363
364 SortType getSortType(int column) const override
365 {
366 if (column == 5) return SortAlphabetical;
367 return SortNumeric;
368 }
369
370 /**
371 * NoteExportable methods.
372 */
373
374 NoteList getNotes() const override {
375 return getNotesStartingWithin(getStartFrame(),
376 getEndFrame() - getStartFrame());
377 }
378
379 NoteList getNotesActiveAt(sv_frame_t frame) const override {
380
381 NoteList notes;
382 EventVector ee = m_events.getEventsCovering(frame);
383 for (const auto &e: ee) {
384 notes.push_back(e.toNoteData(getSampleRate(),
385 getScaleUnits() != "Hz"));
386 }
387 return notes;
388 }
389
390 NoteList getNotesStartingWithin(sv_frame_t startFrame,
391 sv_frame_t duration) const override {
392
393 NoteList notes;
394 EventVector ee = m_events.getEventsStartingWithin(startFrame, duration);
395 for (const auto &e: ee) {
396 notes.push_back(e.toNoteData(getSampleRate(),
397 getScaleUnits() != "Hz"));
398 }
399 return notes;
400 }
401
402 /**
403 * XmlExportable methods.
404 */
148 405
149 void toXml(QTextStream &out, 406 void toXml(QTextStream &out,
150 QString indent = "", 407 QString indent = "",
151 QString extraAttributes = "") const override { 408 QString extraAttributes = "") const override {
152 409
169 .arg(extraAttributes)); 426 .arg(extraAttributes));
170 427
171 m_events.toXml(out, indent, QString("dimensions=\"3\"")); 428 m_events.toXml(out, indent, QString("dimensions=\"3\""));
172 } 429 }
173 430
174 /**
175 * TabularModel methods.
176 */
177
178 int getRowCount() const override {
179 return m_events.count();
180 }
181
182 int getColumnCount() const override {
183 return 6;
184 }
185
186 bool isColumnTimeValue(int column) const override {
187 // NB duration is not a "time value" -- that's for columns
188 // whose sort ordering is exactly that of the frame time
189 return (column < 2);
190 }
191
192 sv_frame_t getFrameForRow(int row) const override {
193 if (row < 0 || row >= m_events.count()) {
194 return 0;
195 }
196 Event e = m_events.getEventByIndex(row);
197 return e.getFrame();
198 }
199
200 int getRowForFrame(sv_frame_t frame) const override {
201 return m_events.getIndexForEvent(Event(frame));
202 }
203
204 QString getHeading(int column) const override {
205 switch (column) {
206 case 0: return tr("Time");
207 case 1: return tr("Frame");
208 case 2: return tr("Pitch");
209 case 3: return tr("Duration");
210 case 4: return tr("Level");
211 case 5: return tr("Label");
212 default: return tr("Unknown");
213 }
214 }
215
216 QVariant getData(int row, int column, int role) const override {
217
218 if (row < 0 || row >= m_events.count()) {
219 return QVariant();
220 }
221
222 Event e = m_events.getEventByIndex(row);
223
224 switch (column) {
225 case 0: return adaptFrameForRole(e.getFrame(), getSampleRate(), role);
226 case 1: return int(e.getFrame());
227 case 2: return adaptValueForRole(e.getValue(), getScaleUnits(), role);
228 case 3: return int(e.getDuration());
229 case 4: return e.getLevel();
230 case 5: return e.getLabel();
231 default: return QVariant();
232 }
233 }
234
235 class EditCommand : public Command
236 {
237 public:
238 //!!! borrowed ptr
239 EditCommand(NoteModel *model, QString name) :
240 m_model(model), m_name(name) { }
241
242 QString getName() const override {
243 return m_name;
244 }
245
246 void addPoint(Event e) {
247 m_add.insert(e);
248 }
249 void deletePoint(Event e) {
250 m_remove.insert(e);
251 }
252
253 void execute() override {
254 for (const Event &e: m_add) m_model->addPoint(e);
255 for (const Event &e: m_remove) m_model->deletePoint(e);
256 }
257
258 void unexecute() override {
259 for (const Event &e: m_remove) m_model->addPoint(e);
260 for (const Event &e: m_add) m_model->deletePoint(e);
261 }
262
263 private:
264 NoteModel *m_model;
265 std::set<Event> m_add;
266 std::set<Event> m_remove;
267 QString m_name;
268 };
269
270 //!!! rename Point to Note throughout? Just because we can now?
271 void addPoint(Event e) {
272
273 bool allChange = false;
274
275 {
276 QMutexLocker locker(&m_mutex);
277 m_events.add(e);
278 //!!!??? if (point.getLabel() != "") m_hasTextLabels = true;
279
280 float v = e.getValue();
281 if (!ISNAN(v) && !ISINF(v)) {
282 if (!m_haveExtents || v < m_valueMinimum) {
283 m_valueMinimum = v; allChange = true;
284 }
285 if (!m_haveExtents || v > m_valueMaximum) {
286 m_valueMaximum = v; allChange = true;
287 }
288 m_haveExtents = true;
289 }
290
291 sv_frame_t f = e.getFrame();
292
293 if (!m_notifyOnAdd) {
294 if (m_sinceLastNotifyMin == -1 || f < m_sinceLastNotifyMin) {
295 m_sinceLastNotifyMin = f;
296 }
297 if (m_sinceLastNotifyMax == -1 || f > m_sinceLastNotifyMax) {
298 m_sinceLastNotifyMax = f;
299 }
300 }
301 }
302
303 if (m_notifyOnAdd) {
304 emit modelChangedWithin(e.getFrame(),
305 e.getFrame() + e.getDuration() + m_resolution);
306 }
307 if (allChange) {
308 emit modelChanged();
309 }
310 }
311
312 void deletePoint(Event e) {
313 {
314 QMutexLocker locker(&m_mutex);
315 m_events.remove(e);
316 }
317 emit modelChangedWithin(e.getFrame(),
318 e.getFrame() + e.getDuration() + m_resolution);
319 }
320
321 EventVector getPoints() const /*!!! override? - and/or rename? */ {
322 EventVector ee;
323 for (int i = 0; i < m_events.count(); ++i) {
324 ee.push_back(m_events.getEventByIndex(i));
325 }
326 return ee;
327 }
328
329 //!!! bleah
330 EventVector getPoints(sv_frame_t start, sv_frame_t end) const {
331 return m_events.getEventsSpanning(start, end - start);
332 }
333
334 int getPointCount() const {
335 return m_events.count();
336 }
337
338 bool isEmpty() const {
339 return m_events.isEmpty();
340 }
341
342 bool containsPoint(const Event &e) const {
343 return m_events.contains(e);
344 }
345
346 Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override
347 {
348 if (row < 0 || row >= m_events.count()) return nullptr;
349 if (role != Qt::EditRole) return nullptr;
350
351 Event e0 = m_events.getEventByIndex(row);
352 Event e1;
353
354 switch (column) {
355 case 0: e1 = e0.withFrame(sv_frame_t(round(value.toDouble() *
356 getSampleRate()))); break;
357 case 1: e1 = e0.withFrame(value.toInt()); break;
358 case 2: e1 = e0.withValue(float(value.toDouble())); break;
359 case 3: e1 = e0.withDuration(value.toInt()); break;
360 case 4: e1 = e0.withLevel(float(value.toDouble())); break;
361 case 5: e1 = e0.withLabel(value.toString()); break;
362 }
363
364 EditCommand *command = new EditCommand(this, tr("Edit Data"));
365 command->deletePoint(e0);
366 command->addPoint(e1);
367 return command;
368 }
369
370 SortType getSortType(int column) const override
371 {
372 if (column == 5) return SortAlphabetical;
373 return SortNumeric;
374 }
375
376 /**
377 * NoteExportable methods.
378 */
379
380 NoteList getNotes() const override {
381 return getNotesStartingWithin(getStartFrame(),
382 getEndFrame() - getStartFrame());
383 }
384
385 NoteList getNotesActiveAt(sv_frame_t frame) const override {
386
387 NoteList notes;
388 EventVector ee = m_events.getEventsCovering(frame);
389 for (const auto &e: ee) {
390 notes.push_back(e.toNoteData(getSampleRate(),
391 getScaleUnits() != "Hz"));
392 }
393 return notes;
394 }
395
396 NoteList getNotesStartingWithin(sv_frame_t startFrame,
397 sv_frame_t duration) const override {
398
399 NoteList notes;
400 EventVector ee = m_events.getEventsStartingWithin(startFrame, duration);
401 for (const auto &e: ee) {
402 notes.push_back(e.toNoteData(getSampleRate(),
403 getScaleUnits() != "Hz"));
404 }
405 return notes;
406 }
407
408 protected: 431 protected:
409 sv_samplerate_t m_sampleRate; 432 sv_samplerate_t m_sampleRate;
410 int m_resolution; 433 int m_resolution;
411 434
412 float m_valueMinimum; 435 float m_valueMinimum;