Mercurial > hg > svgui
comparison layer/NoteLayer.cpp @ 1486:ac0a8addabcf
Merge from branch by-id
author | Chris Cannam |
---|---|
date | Wed, 17 Jul 2019 14:25:16 +0100 |
parents | e540aa5d89cd |
children | 0fa49a6ce64f |
comparison
equal
deleted
inserted
replaced
1468:de41a11cabc2 | 1486:ac0a8addabcf |
---|---|
46 | 46 |
47 //#define DEBUG_NOTE_LAYER 1 | 47 //#define DEBUG_NOTE_LAYER 1 |
48 | 48 |
49 NoteLayer::NoteLayer() : | 49 NoteLayer::NoteLayer() : |
50 SingleColourLayer(), | 50 SingleColourLayer(), |
51 m_model(nullptr), | |
52 m_editing(false), | 51 m_editing(false), |
53 m_dragPointX(0), | 52 m_dragPointX(0), |
54 m_dragPointY(0), | 53 m_dragPointY(0), |
55 m_dragStartX(0), | 54 m_dragStartX(0), |
56 m_dragStartY(0), | 55 m_dragStartY(0), |
63 m_scaleMaximum(0) | 62 m_scaleMaximum(0) |
64 { | 63 { |
65 SVDEBUG << "constructed NoteLayer" << endl; | 64 SVDEBUG << "constructed NoteLayer" << endl; |
66 } | 65 } |
67 | 66 |
68 void | 67 int |
69 NoteLayer::setModel(NoteModel *model) | 68 NoteLayer::getCompletion(LayerGeometryProvider *) const |
70 { | 69 { |
71 if (m_model == model) return; | 70 auto model = ModelById::get(m_model); |
72 m_model = model; | 71 if (model) return model->getCompletion(); |
73 | 72 else return 0; |
74 connectSignals(m_model); | 73 } |
75 | 74 |
76 // SVDEBUG << "NoteLayer::setModel(" << model << ")" << endl; | 75 void |
77 | 76 NoteLayer::setModel(ModelId modelId) |
77 { | |
78 auto newModel = ModelById::getAs<NoteModel>(modelId); | |
79 | |
80 if (!modelId.isNone() && !newModel) { | |
81 throw std::logic_error("Not a NoteModel"); | |
82 } | |
83 | |
84 if (m_model == modelId) return; | |
85 m_model = modelId; | |
86 | |
87 if (newModel) { | |
88 connectSignals(m_model); | |
89 } | |
90 | |
78 m_scaleMinimum = 0; | 91 m_scaleMinimum = 0; |
79 m_scaleMaximum = 0; | 92 m_scaleMaximum = 0; |
80 | 93 |
81 emit modelReplaced(); | 94 emit modelReplaced(); |
82 } | 95 } |
116 } | 129 } |
117 | 130 |
118 QString | 131 QString |
119 NoteLayer::getScaleUnits() const | 132 NoteLayer::getScaleUnits() const |
120 { | 133 { |
121 if (m_model) return m_model->getScaleUnits(); | 134 auto model = ModelById::getAs<NoteModel>(m_model); |
135 if (model) return model->getScaleUnits(); | |
122 else return ""; | 136 else return ""; |
123 } | 137 } |
124 | 138 |
125 int | 139 int |
126 NoteLayer::getPropertyRangeAndValue(const PropertyName &name, | 140 NoteLayer::getPropertyRangeAndValue(const PropertyName &name, |
137 val = int(m_verticalScale); | 151 val = int(m_verticalScale); |
138 | 152 |
139 } else if (name == "Scale Units") { | 153 } else if (name == "Scale Units") { |
140 | 154 |
141 if (deflt) *deflt = 0; | 155 if (deflt) *deflt = 0; |
142 if (m_model) { | 156 auto model = ModelById::getAs<NoteModel>(m_model); |
157 if (model) { | |
143 val = UnitDatabase::getInstance()->getUnitId | 158 val = UnitDatabase::getInstance()->getUnitId |
144 (getScaleUnits()); | 159 (model->getScaleUnits()); |
145 } | 160 } |
146 | 161 |
147 } else { | 162 } else { |
148 | 163 |
149 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt); | 164 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt); |
172 NoteLayer::setProperty(const PropertyName &name, int value) | 187 NoteLayer::setProperty(const PropertyName &name, int value) |
173 { | 188 { |
174 if (name == "Vertical Scale") { | 189 if (name == "Vertical Scale") { |
175 setVerticalScale(VerticalScale(value)); | 190 setVerticalScale(VerticalScale(value)); |
176 } else if (name == "Scale Units") { | 191 } else if (name == "Scale Units") { |
177 if (m_model) { | 192 auto model = ModelById::getAs<NoteModel>(m_model); |
178 m_model->setScaleUnits | 193 if (model) { |
194 model->setScaleUnits | |
179 (UnitDatabase::getInstance()->getUnitById(value)); | 195 (UnitDatabase::getInstance()->getUnitById(value)); |
180 emit modelChanged(); | 196 emit modelChanged(m_model); |
181 } | 197 } |
182 } else { | 198 } else { |
183 return SingleColourLayer::setProperty(name, value); | 199 return SingleColourLayer::setProperty(name, value); |
184 } | 200 } |
185 } | 201 } |
212 | 228 |
213 bool | 229 bool |
214 NoteLayer::getValueExtents(double &min, double &max, | 230 NoteLayer::getValueExtents(double &min, double &max, |
215 bool &logarithmic, QString &unit) const | 231 bool &logarithmic, QString &unit) const |
216 { | 232 { |
217 if (!m_model) return false; | 233 auto model = ModelById::getAs<NoteModel>(m_model); |
218 min = m_model->getValueMinimum(); | 234 if (!model) return false; |
219 max = m_model->getValueMaximum(); | 235 min = model->getValueMinimum(); |
236 max = model->getValueMaximum(); | |
220 | 237 |
221 if (shouldConvertMIDIToHz()) { | 238 if (shouldConvertMIDIToHz()) { |
222 unit = "Hz"; | 239 unit = "Hz"; |
223 min = Pitch::getFrequencyForPitch(int(lrint(min))); | 240 min = Pitch::getFrequencyForPitch(int(lrint(min))); |
224 max = Pitch::getFrequencyForPitch(int(lrint(max + 1))); | 241 max = Pitch::getFrequencyForPitch(int(lrint(max + 1))); |
225 } else unit = getScaleUnits(); | 242 } else unit = getScaleUnits(); |
226 | 243 |
227 if (m_verticalScale == MIDIRangeScale || | 244 if (m_verticalScale == MIDIRangeScale || |
228 m_verticalScale == LogScale) logarithmic = true; | 245 m_verticalScale == LogScale) { |
246 logarithmic = true; | |
247 } | |
229 | 248 |
230 return true; | 249 return true; |
231 } | 250 } |
232 | 251 |
233 bool | 252 bool |
234 NoteLayer::getDisplayExtents(double &min, double &max) const | 253 NoteLayer::getDisplayExtents(double &min, double &max) const |
235 { | 254 { |
236 if (!m_model || shouldAutoAlign()) return false; | 255 auto model = ModelById::getAs<NoteModel>(m_model); |
256 if (!model || shouldAutoAlign()) return false; | |
237 | 257 |
238 if (m_verticalScale == MIDIRangeScale) { | 258 if (m_verticalScale == MIDIRangeScale) { |
239 min = Pitch::getFrequencyForPitch(0); | 259 min = Pitch::getFrequencyForPitch(0); |
240 max = Pitch::getFrequencyForPitch(127); | 260 max = Pitch::getFrequencyForPitch(127); |
241 return true; | 261 return true; |
242 } | 262 } |
243 | 263 |
244 if (m_scaleMinimum == m_scaleMaximum) { | 264 if (m_scaleMinimum == m_scaleMaximum) { |
245 min = m_model->getValueMinimum(); | 265 min = model->getValueMinimum(); |
246 max = m_model->getValueMaximum(); | 266 max = model->getValueMaximum(); |
247 } else { | 267 } else { |
248 min = m_scaleMinimum; | 268 min = m_scaleMinimum; |
249 max = m_scaleMaximum; | 269 max = m_scaleMaximum; |
250 } | 270 } |
251 | 271 |
262 } | 282 } |
263 | 283 |
264 bool | 284 bool |
265 NoteLayer::setDisplayExtents(double min, double max) | 285 NoteLayer::setDisplayExtents(double min, double max) |
266 { | 286 { |
267 if (!m_model) return false; | 287 if (m_model.isNone()) return false; |
268 | 288 |
269 if (min == max) { | 289 if (min == max) { |
270 if (min == 0.f) { | 290 if (min == 0.f) { |
271 max = 1.f; | 291 max = 1.f; |
272 } else { | 292 } else { |
286 } | 306 } |
287 | 307 |
288 int | 308 int |
289 NoteLayer::getVerticalZoomSteps(int &defaultStep) const | 309 NoteLayer::getVerticalZoomSteps(int &defaultStep) const |
290 { | 310 { |
291 if (shouldAutoAlign()) return 0; | 311 if (shouldAutoAlign() || m_model.isNone()) return 0; |
292 if (!m_model) return 0; | |
293 | |
294 defaultStep = 0; | 312 defaultStep = 0; |
295 return 100; | 313 return 100; |
296 } | 314 } |
297 | 315 |
298 int | 316 int |
299 NoteLayer::getCurrentVerticalZoomStep() const | 317 NoteLayer::getCurrentVerticalZoomStep() const |
300 { | 318 { |
301 if (shouldAutoAlign()) return 0; | 319 if (shouldAutoAlign() || m_model.isNone()) return 0; |
302 if (!m_model) return 0; | |
303 | 320 |
304 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); | 321 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); |
305 if (!mapper) return 0; | 322 if (!mapper) return 0; |
306 | 323 |
307 double dmin, dmax; | 324 double dmin, dmax; |
317 //!!! lots of duplication with TimeValueLayer | 334 //!!! lots of duplication with TimeValueLayer |
318 | 335 |
319 void | 336 void |
320 NoteLayer::setVerticalZoomStep(int step) | 337 NoteLayer::setVerticalZoomStep(int step) |
321 { | 338 { |
322 if (shouldAutoAlign()) return; | 339 if (shouldAutoAlign() || m_model.isNone()) return; |
323 if (!m_model) return; | |
324 | 340 |
325 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); | 341 RangeMapper *mapper = getNewVerticalZoomRangeMapper(); |
326 if (!mapper) return; | 342 if (!mapper) return; |
327 | 343 |
328 double min, max; | 344 double min, max; |
368 } | 384 } |
369 | 385 |
370 RangeMapper * | 386 RangeMapper * |
371 NoteLayer::getNewVerticalZoomRangeMapper() const | 387 NoteLayer::getNewVerticalZoomRangeMapper() const |
372 { | 388 { |
373 if (!m_model) return nullptr; | 389 if (m_model.isNone()) return nullptr; |
374 | 390 |
375 RangeMapper *mapper; | 391 RangeMapper *mapper; |
376 | 392 |
377 double min, max; | 393 double min, max; |
378 bool logarithmic; | 394 bool logarithmic; |
391 } | 407 } |
392 | 408 |
393 EventVector | 409 EventVector |
394 NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const | 410 NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const |
395 { | 411 { |
396 if (!m_model) return {}; | 412 auto model = ModelById::getAs<NoteModel>(m_model); |
413 if (!model) return {}; | |
397 | 414 |
398 sv_frame_t frame = v->getFrameForX(x); | 415 sv_frame_t frame = v->getFrameForX(x); |
399 | 416 |
400 EventVector local = m_model->getEventsCovering(frame); | 417 EventVector local = model->getEventsCovering(frame); |
401 if (!local.empty()) return local; | 418 if (!local.empty()) return local; |
402 | 419 |
403 int fuzz = ViewManager::scalePixelSize(2); | 420 int fuzz = ViewManager::scalePixelSize(2); |
404 sv_frame_t start = v->getFrameForX(x - fuzz); | 421 sv_frame_t start = v->getFrameForX(x - fuzz); |
405 sv_frame_t end = v->getFrameForX(x + fuzz); | 422 sv_frame_t end = v->getFrameForX(x + fuzz); |
406 | 423 |
407 local = m_model->getEventsStartingWithin(frame, end - frame); | 424 local = model->getEventsStartingWithin(frame, end - frame); |
408 if (!local.empty()) return local; | 425 if (!local.empty()) return local; |
409 | 426 |
410 local = m_model->getEventsSpanning(start, frame - start); | 427 local = model->getEventsSpanning(start, frame - start); |
411 if (!local.empty()) return local; | 428 if (!local.empty()) return local; |
412 | 429 |
413 return {}; | 430 return {}; |
414 } | 431 } |
415 | 432 |
416 bool | 433 bool |
417 NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &point) const | 434 NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &point) const |
418 { | 435 { |
419 if (!m_model) return false; | 436 auto model = ModelById::getAs<NoteModel>(m_model); |
437 if (!model) return false; | |
420 | 438 |
421 sv_frame_t frame = v->getFrameForX(x); | 439 sv_frame_t frame = v->getFrameForX(x); |
422 | 440 |
423 EventVector onPoints = m_model->getEventsCovering(frame); | 441 EventVector onPoints = model->getEventsCovering(frame); |
424 if (onPoints.empty()) return false; | 442 if (onPoints.empty()) return false; |
425 | 443 |
426 int nearestDistance = -1; | 444 int nearestDistance = -1; |
427 for (const auto &p: onPoints) { | 445 for (const auto &p: onPoints) { |
428 int distance = getYForValue(v, p.getValue()) - y; | 446 int distance = getYForValue(v, p.getValue()) - y; |
439 QString | 457 QString |
440 NoteLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const | 458 NoteLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const |
441 { | 459 { |
442 int x = pos.x(); | 460 int x = pos.x(); |
443 | 461 |
444 if (!m_model || !m_model->getSampleRate()) return ""; | 462 auto model = ModelById::getAs<NoteModel>(m_model); |
463 if (!model || !model->getSampleRate()) return ""; | |
445 | 464 |
446 EventVector points = getLocalPoints(v, x); | 465 EventVector points = getLocalPoints(v, x); |
447 | 466 |
448 if (points.empty()) { | 467 if (points.empty()) { |
449 if (!m_model->isReady()) { | 468 if (!model->isReady()) { |
450 return tr("In progress"); | 469 return tr("In progress"); |
451 } else { | 470 } else { |
452 return tr("No local points"); | 471 return tr("No local points"); |
453 } | 472 } |
454 } | 473 } |
459 for (i = points.begin(); i != points.end(); ++i) { | 478 for (i = points.begin(); i != points.end(); ++i) { |
460 | 479 |
461 int y = getYForValue(v, i->getValue()); | 480 int y = getYForValue(v, i->getValue()); |
462 int h = 3; | 481 int h = 3; |
463 | 482 |
464 if (m_model->getValueQuantization() != 0.0) { | 483 if (model->getValueQuantization() != 0.0) { |
465 h = y - getYForValue | 484 h = y - getYForValue |
466 (v, i->getValue() + m_model->getValueQuantization()); | 485 (v, i->getValue() + model->getValueQuantization()); |
467 if (h < 3) h = 3; | 486 if (h < 3) h = 3; |
468 } | 487 } |
469 | 488 |
470 if (pos.y() >= y - h && pos.y() <= y) { | 489 if (pos.y() >= y - h && pos.y() <= y) { |
471 note = *i; | 490 note = *i; |
474 } | 493 } |
475 | 494 |
476 if (i == points.end()) return tr("No local points"); | 495 if (i == points.end()) return tr("No local points"); |
477 | 496 |
478 RealTime rt = RealTime::frame2RealTime(note.getFrame(), | 497 RealTime rt = RealTime::frame2RealTime(note.getFrame(), |
479 m_model->getSampleRate()); | 498 model->getSampleRate()); |
480 RealTime rd = RealTime::frame2RealTime(note.getDuration(), | 499 RealTime rd = RealTime::frame2RealTime(note.getDuration(), |
481 m_model->getSampleRate()); | 500 model->getSampleRate()); |
482 | 501 |
483 QString pitchText; | 502 QString pitchText; |
484 | 503 |
485 float value = note.getValue(); | 504 float value = note.getValue(); |
486 | 505 |
528 bool | 547 bool |
529 NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, | 548 NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, |
530 int &resolution, | 549 int &resolution, |
531 SnapType snap) const | 550 SnapType snap) const |
532 { | 551 { |
533 if (!m_model) { | 552 auto model = ModelById::getAs<NoteModel>(m_model); |
553 if (!model) { | |
534 return Layer::snapToFeatureFrame(v, frame, resolution, snap); | 554 return Layer::snapToFeatureFrame(v, frame, resolution, snap); |
535 } | 555 } |
536 | 556 |
537 // SnapLeft / SnapRight: return frame of nearest feature in that | 557 // SnapLeft / SnapRight: return frame of nearest feature in that |
538 // direction no matter how far away | 558 // direction no matter how far away |
539 // | 559 // |
540 // SnapNeighbouring: return frame of feature that would be used in | 560 // SnapNeighbouring: return frame of feature that would be used in |
541 // an editing operation, i.e. closest feature in either direction | 561 // an editing operation, i.e. closest feature in either direction |
542 // but only if it is "close enough" | 562 // but only if it is "close enough" |
543 | 563 |
544 resolution = m_model->getResolution(); | 564 resolution = model->getResolution(); |
545 | 565 |
546 if (snap == SnapNeighbouring) { | 566 if (snap == SnapNeighbouring) { |
547 EventVector points = getLocalPoints(v, v->getXForFrame(frame)); | 567 EventVector points = getLocalPoints(v, v->getXForFrame(frame)); |
548 if (points.empty()) return false; | 568 if (points.empty()) return false; |
549 frame = points.begin()->getFrame(); | 569 frame = points.begin()->getFrame(); |
550 return true; | 570 return true; |
551 } | 571 } |
552 | 572 |
553 Event e; | 573 Event e; |
554 if (m_model->getNearestEventMatching | 574 if (model->getNearestEventMatching |
555 (frame, | 575 (frame, |
556 [](Event) { return true; }, | 576 [](Event) { return true; }, |
557 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, | 577 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, |
558 e)) { | 578 e)) { |
559 frame = e.getFrame(); | 579 frame = e.getFrame(); |
568 { | 588 { |
569 min = 0.0; | 589 min = 0.0; |
570 max = 0.0; | 590 max = 0.0; |
571 log = false; | 591 log = false; |
572 | 592 |
593 auto model = ModelById::getAs<NoteModel>(m_model); | |
594 if (!model) return; | |
595 | |
573 QString queryUnits; | 596 QString queryUnits; |
574 if (shouldConvertMIDIToHz()) queryUnits = "Hz"; | 597 if (shouldConvertMIDIToHz()) queryUnits = "Hz"; |
575 else queryUnits = getScaleUnits(); | 598 else queryUnits = getScaleUnits(); |
576 | 599 |
577 if (shouldAutoAlign()) { | 600 if (shouldAutoAlign()) { |
578 | 601 |
579 if (!v->getValueExtents(queryUnits, min, max, log)) { | 602 if (!v->getValueExtents(queryUnits, min, max, log)) { |
580 | 603 |
581 min = m_model->getValueMinimum(); | 604 min = model->getValueMinimum(); |
582 max = m_model->getValueMaximum(); | 605 max = model->getValueMaximum(); |
583 | 606 |
584 if (shouldConvertMIDIToHz()) { | 607 if (shouldConvertMIDIToHz()) { |
585 min = Pitch::getFrequencyForPitch(int(lrint(min))); | 608 min = Pitch::getFrequencyForPitch(int(lrint(min))); |
586 max = Pitch::getFrequencyForPitch(int(lrint(max + 1))); | 609 max = Pitch::getFrequencyForPitch(int(lrint(max + 1))); |
587 } | 610 } |
679 } | 702 } |
680 | 703 |
681 bool | 704 bool |
682 NoteLayer::shouldAutoAlign() const | 705 NoteLayer::shouldAutoAlign() const |
683 { | 706 { |
684 if (!m_model) return false; | 707 if (m_model.isNone()) return false; |
685 return (m_verticalScale == AutoAlignScale); | 708 return (m_verticalScale == AutoAlignScale); |
686 } | 709 } |
687 | 710 |
688 void | 711 void |
689 NoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const | 712 NoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const |
690 { | 713 { |
691 if (!m_model || !m_model->isOK()) return; | 714 auto model = ModelById::getAs<NoteModel>(m_model); |
692 | 715 if (!model || !model->isOK()) return; |
693 sv_samplerate_t sampleRate = m_model->getSampleRate(); | 716 |
717 sv_samplerate_t sampleRate = model->getSampleRate(); | |
694 if (!sampleRate) return; | 718 if (!sampleRate) return; |
695 | 719 |
696 // Profiler profiler("NoteLayer::paint", true); | 720 // Profiler profiler("NoteLayer::paint", true); |
697 | 721 |
698 int x0 = rect.left(), x1 = rect.right(); | 722 int x0 = rect.left(), x1 = rect.right(); |
699 sv_frame_t frame0 = v->getFrameForX(x0); | 723 sv_frame_t frame0 = v->getFrameForX(x0); |
700 sv_frame_t frame1 = v->getFrameForX(x1); | 724 sv_frame_t frame1 = v->getFrameForX(x1); |
701 | 725 |
702 EventVector points(m_model->getEventsSpanning(frame0, frame1 - frame0)); | 726 EventVector points(model->getEventsSpanning(frame0, frame1 - frame0)); |
703 if (points.empty()) return; | 727 if (points.empty()) return; |
704 | 728 |
705 paint.setPen(getBaseQColor()); | 729 paint.setPen(getBaseQColor()); |
706 | 730 |
707 QColor brushColour(getBaseQColor()); | 731 QColor brushColour(getBaseQColor()); |
708 brushColour.setAlpha(80); | 732 brushColour.setAlpha(80); |
709 | 733 |
710 // SVDEBUG << "NoteLayer::paint: resolution is " | 734 // SVDEBUG << "NoteLayer::paint: resolution is " |
711 // << m_model->getResolution() << " frames" << endl; | 735 // << model->getResolution() << " frames" << endl; |
712 | 736 |
713 double min = m_model->getValueMinimum(); | 737 double min = model->getValueMinimum(); |
714 double max = m_model->getValueMaximum(); | 738 double max = model->getValueMaximum(); |
715 if (max == min) max = min + 1.0; | 739 if (max == min) max = min + 1.0; |
716 | 740 |
717 QPoint localPos; | 741 QPoint localPos; |
718 Event illuminatePoint; | 742 Event illuminatePoint; |
719 bool shouldIlluminate = false; | 743 bool shouldIlluminate = false; |
737 int x = v->getXForFrame(p.getFrame()); | 761 int x = v->getXForFrame(p.getFrame()); |
738 int y = getYForValue(v, p.getValue()); | 762 int y = getYForValue(v, p.getValue()); |
739 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x; | 763 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x; |
740 int h = 3; | 764 int h = 3; |
741 | 765 |
742 if (m_model->getValueQuantization() != 0.0) { | 766 if (model->getValueQuantization() != 0.0) { |
743 h = y - getYForValue(v, p.getValue() + m_model->getValueQuantization()); | 767 h = y - getYForValue(v, p.getValue() + model->getValueQuantization()); |
744 if (h < 3) h = 3; | 768 if (h < 3) h = 3; |
745 } | 769 } |
746 | 770 |
747 if (w < 1) w = 1; | 771 if (w < 1) w = 1; |
748 paint.setPen(getBaseQColor()); | 772 paint.setPen(getBaseQColor()); |
750 | 774 |
751 if (shouldIlluminate && illuminatePoint == p) { | 775 if (shouldIlluminate && illuminatePoint == p) { |
752 | 776 |
753 paint.setPen(v->getForeground()); | 777 paint.setPen(v->getForeground()); |
754 paint.setBrush(v->getForeground()); | 778 paint.setBrush(v->getForeground()); |
779 | |
780 // Qt 5.13 deprecates QFontMetrics::width(), but its suggested | |
781 // replacement (horizontalAdvance) was only added in Qt 5.11 | |
782 // which is too new for us | |
783 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
755 | 784 |
756 QString vlabel = QString("%1%2").arg(p.getValue()).arg(getScaleUnits()); | 785 QString vlabel = QString("%1%2").arg(p.getValue()).arg(getScaleUnits()); |
757 PaintAssistant::drawVisibleText(v, paint, | 786 PaintAssistant::drawVisibleText(v, paint, |
758 x - paint.fontMetrics().width(vlabel) - 2, | 787 x - paint.fontMetrics().width(vlabel) - 2, |
759 y + paint.fontMetrics().height()/2 | 788 y + paint.fontMetrics().height()/2 |
760 - paint.fontMetrics().descent(), | 789 - paint.fontMetrics().descent(), |
761 vlabel, PaintAssistant::OutlinedText); | 790 vlabel, PaintAssistant::OutlinedText); |
762 | 791 |
763 QString hlabel = RealTime::frame2RealTime | 792 QString hlabel = RealTime::frame2RealTime |
764 (p.getFrame(), m_model->getSampleRate()).toText(true).c_str(); | 793 (p.getFrame(), model->getSampleRate()).toText(true).c_str(); |
765 PaintAssistant::drawVisibleText(v, paint, | 794 PaintAssistant::drawVisibleText(v, paint, |
766 x, | 795 x, |
767 y - h/2 - paint.fontMetrics().descent() - 2, | 796 y - h/2 - paint.fontMetrics().descent() - 2, |
768 hlabel, PaintAssistant::OutlinedText); | 797 hlabel, PaintAssistant::OutlinedText); |
769 } | 798 } |
775 } | 804 } |
776 | 805 |
777 int | 806 int |
778 NoteLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const | 807 NoteLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const |
779 { | 808 { |
780 if (!m_model) { | 809 if (m_model.isNone()) { |
781 return 0; | 810 return 0; |
782 } | 811 } |
783 | 812 |
784 if (shouldAutoAlign() && !valueExtentsMatchMine(v)) { | 813 if (shouldAutoAlign() && !valueExtentsMatchMine(v)) { |
785 return 0; | 814 return 0; |
793 } | 822 } |
794 | 823 |
795 void | 824 void |
796 NoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const | 825 NoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const |
797 { | 826 { |
798 if (!m_model || m_model->isEmpty()) return; | 827 auto model = ModelById::getAs<NoteModel>(m_model); |
828 if (!model || model->isEmpty()) return; | |
799 | 829 |
800 QString unit; | 830 QString unit; |
801 double min, max; | 831 double min, max; |
802 bool logarithmic; | 832 bool logarithmic; |
803 | 833 |
833 void | 863 void |
834 NoteLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) | 864 NoteLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) |
835 { | 865 { |
836 // SVDEBUG << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; | 866 // SVDEBUG << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; |
837 | 867 |
838 if (!m_model) return; | 868 auto model = ModelById::getAs<NoteModel>(m_model); |
869 if (!model) return; | |
839 | 870 |
840 sv_frame_t frame = v->getFrameForX(e->x()); | 871 sv_frame_t frame = v->getFrameForX(e->x()); |
841 if (frame < 0) frame = 0; | 872 if (frame < 0) frame = 0; |
842 frame = frame / m_model->getResolution() * m_model->getResolution(); | 873 frame = frame / model->getResolution() * model->getResolution(); |
843 | 874 |
844 double value = getValueForY(v, e->y()); | 875 double value = getValueForY(v, e->y()); |
845 | 876 |
846 m_editingPoint = Event(frame, float(value), 0, 0.8f, tr("New Point")); | 877 m_editingPoint = Event(frame, float(value), 0, 0.8f, tr("New Point")); |
847 m_originalPoint = m_editingPoint; | 878 m_originalPoint = m_editingPoint; |
848 | 879 |
849 if (m_editingCommand) finish(m_editingCommand); | 880 if (m_editingCommand) finish(m_editingCommand); |
850 m_editingCommand = new ChangeEventsCommand(m_model, tr("Draw Point")); | 881 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Draw Point")); |
851 m_editingCommand->add(m_editingPoint); | 882 m_editingCommand->add(m_editingPoint); |
852 | 883 |
853 m_editing = true; | 884 m_editing = true; |
854 } | 885 } |
855 | 886 |
856 void | 887 void |
857 NoteLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) | 888 NoteLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) |
858 { | 889 { |
859 // SVDEBUG << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; | 890 // SVDEBUG << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; |
860 | 891 |
861 if (!m_model || !m_editing) return; | 892 auto model = ModelById::getAs<NoteModel>(m_model); |
893 if (!model || !m_editing) return; | |
862 | 894 |
863 sv_frame_t frame = v->getFrameForX(e->x()); | 895 sv_frame_t frame = v->getFrameForX(e->x()); |
864 if (frame < 0) frame = 0; | 896 if (frame < 0) frame = 0; |
865 frame = frame / m_model->getResolution() * m_model->getResolution(); | 897 frame = frame / model->getResolution() * model->getResolution(); |
866 | 898 |
867 double newValue = getValueForY(v, e->y()); | 899 double newValue = getValueForY(v, e->y()); |
868 | 900 |
869 sv_frame_t newFrame = m_editingPoint.getFrame(); | 901 sv_frame_t newFrame = m_editingPoint.getFrame(); |
870 sv_frame_t newDuration = frame - newFrame; | 902 sv_frame_t newDuration = frame - newFrame; |
885 | 917 |
886 void | 918 void |
887 NoteLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) | 919 NoteLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) |
888 { | 920 { |
889 // SVDEBUG << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl; | 921 // SVDEBUG << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl; |
890 if (!m_model || !m_editing) return; | 922 auto model = ModelById::getAs<NoteModel>(m_model); |
923 if (!model || !m_editing) return; | |
891 finish(m_editingCommand); | 924 finish(m_editingCommand); |
892 m_editingCommand = nullptr; | 925 m_editingCommand = nullptr; |
893 m_editing = false; | 926 m_editing = false; |
894 } | 927 } |
895 | 928 |
896 void | 929 void |
897 NoteLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) | 930 NoteLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) |
898 { | 931 { |
899 if (!m_model) return; | 932 auto model = ModelById::getAs<NoteModel>(m_model); |
933 if (!model) return; | |
900 | 934 |
901 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; | 935 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; |
902 | 936 |
903 if (m_editingCommand) { | 937 if (m_editingCommand) { |
904 finish(m_editingCommand); | 938 finish(m_editingCommand); |
914 } | 948 } |
915 | 949 |
916 void | 950 void |
917 NoteLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) | 951 NoteLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) |
918 { | 952 { |
919 if (!m_model || !m_editing) return; | 953 auto model = ModelById::getAs<NoteModel>(m_model); |
954 if (!model || !m_editing) return; | |
920 | 955 |
921 m_editing = false; | 956 m_editing = false; |
922 | 957 |
923 Event p(0); | 958 Event p(0); |
924 if (!getPointToDrag(v, e->x(), e->y(), p)) return; | 959 if (!getPointToDrag(v, e->x(), e->y(), p)) return; |
925 if (p.getFrame() != m_editingPoint.getFrame() || | 960 if (p.getFrame() != m_editingPoint.getFrame() || |
926 p.getValue() != m_editingPoint.getValue()) return; | 961 p.getValue() != m_editingPoint.getValue()) return; |
927 | 962 |
928 m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point")); | 963 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Erase Point")); |
929 | 964 |
930 m_editingCommand->remove(m_editingPoint); | 965 m_editingCommand->remove(m_editingPoint); |
931 | 966 |
932 finish(m_editingCommand); | 967 finish(m_editingCommand); |
933 m_editingCommand = nullptr; | 968 m_editingCommand = nullptr; |
937 void | 972 void |
938 NoteLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) | 973 NoteLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) |
939 { | 974 { |
940 // SVDEBUG << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; | 975 // SVDEBUG << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; |
941 | 976 |
942 if (!m_model) return; | 977 auto model = ModelById::getAs<NoteModel>(m_model); |
978 if (!model) return; | |
943 | 979 |
944 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; | 980 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; |
945 m_originalPoint = m_editingPoint; | 981 m_originalPoint = m_editingPoint; |
946 | 982 |
947 m_dragPointX = v->getXForFrame(m_editingPoint.getFrame()); | 983 m_dragPointX = v->getXForFrame(m_editingPoint.getFrame()); |
960 void | 996 void |
961 NoteLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) | 997 NoteLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) |
962 { | 998 { |
963 // SVDEBUG << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl; | 999 // SVDEBUG << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl; |
964 | 1000 |
965 if (!m_model || !m_editing) return; | 1001 auto model = ModelById::getAs<NoteModel>(m_model); |
1002 if (!model || !m_editing) return; | |
966 | 1003 |
967 int xdist = e->x() - m_dragStartX; | 1004 int xdist = e->x() - m_dragStartX; |
968 int ydist = e->y() - m_dragStartY; | 1005 int ydist = e->y() - m_dragStartY; |
969 int newx = m_dragPointX + xdist; | 1006 int newx = m_dragPointX + xdist; |
970 int newy = m_dragPointY + ydist; | 1007 int newy = m_dragPointY + ydist; |
971 | 1008 |
972 sv_frame_t frame = v->getFrameForX(newx); | 1009 sv_frame_t frame = v->getFrameForX(newx); |
973 if (frame < 0) frame = 0; | 1010 if (frame < 0) frame = 0; |
974 frame = frame / m_model->getResolution() * m_model->getResolution(); | 1011 frame = frame / model->getResolution() * model->getResolution(); |
975 | 1012 |
976 double value = getValueForY(v, newy); | 1013 double value = getValueForY(v, newy); |
977 | 1014 |
978 if (!m_editingCommand) { | 1015 if (!m_editingCommand) { |
979 m_editingCommand = new ChangeEventsCommand(m_model, | 1016 m_editingCommand = new ChangeEventsCommand |
980 tr("Drag Point")); | 1017 (m_model.untyped, tr("Drag Point")); |
981 } | 1018 } |
982 | 1019 |
983 m_editingCommand->remove(m_editingPoint); | 1020 m_editingCommand->remove(m_editingPoint); |
984 m_editingPoint = m_editingPoint | 1021 m_editingPoint = m_editingPoint |
985 .withFrame(frame) | 1022 .withFrame(frame) |
989 | 1026 |
990 void | 1027 void |
991 NoteLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) | 1028 NoteLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) |
992 { | 1029 { |
993 // SVDEBUG << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl; | 1030 // SVDEBUG << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl; |
994 if (!m_model || !m_editing) return; | 1031 auto model = ModelById::getAs<NoteModel>(m_model); |
1032 if (!model || !m_editing) return; | |
995 | 1033 |
996 if (m_editingCommand) { | 1034 if (m_editingCommand) { |
997 | 1035 |
998 QString newName = m_editingCommand->getName(); | 1036 QString newName = m_editingCommand->getName(); |
999 | 1037 |
1016 } | 1054 } |
1017 | 1055 |
1018 bool | 1056 bool |
1019 NoteLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) | 1057 NoteLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) |
1020 { | 1058 { |
1021 if (!m_model) return false; | 1059 auto model = ModelById::getAs<NoteModel>(m_model); |
1060 if (!model) return false; | |
1022 | 1061 |
1023 Event note(0); | 1062 Event note(0); |
1024 if (!getPointToDrag(v, e->x(), e->y(), note)) return false; | 1063 if (!getPointToDrag(v, e->x(), e->y(), note)) return false; |
1025 | 1064 |
1026 // Event note = *points.begin(); | 1065 // Event note = *points.begin(); |
1027 | 1066 |
1028 ItemEditDialog *dialog = new ItemEditDialog | 1067 ItemEditDialog *dialog = new ItemEditDialog |
1029 (m_model->getSampleRate(), | 1068 (model->getSampleRate(), |
1030 ItemEditDialog::ShowTime | | 1069 ItemEditDialog::ShowTime | |
1031 ItemEditDialog::ShowDuration | | 1070 ItemEditDialog::ShowDuration | |
1032 ItemEditDialog::ShowValue | | 1071 ItemEditDialog::ShowValue | |
1033 ItemEditDialog::ShowText, | 1072 ItemEditDialog::ShowText, |
1034 getScaleUnits()); | 1073 getScaleUnits()); |
1048 .withValue(dialog->getValue()) | 1087 .withValue(dialog->getValue()) |
1049 .withDuration(dialog->getFrameDuration()) | 1088 .withDuration(dialog->getFrameDuration()) |
1050 .withLabel(dialog->getText()); | 1089 .withLabel(dialog->getText()); |
1051 | 1090 |
1052 ChangeEventsCommand *command = new ChangeEventsCommand | 1091 ChangeEventsCommand *command = new ChangeEventsCommand |
1053 (m_model, tr("Edit Point")); | 1092 (m_model.untyped, tr("Edit Point")); |
1054 command->remove(note); | 1093 command->remove(note); |
1055 command->add(newNote); | 1094 command->add(newNote); |
1056 finish(command); | 1095 finish(command); |
1057 } | 1096 } |
1058 | 1097 |
1064 } | 1103 } |
1065 | 1104 |
1066 void | 1105 void |
1067 NoteLayer::moveSelection(Selection s, sv_frame_t newStartFrame) | 1106 NoteLayer::moveSelection(Selection s, sv_frame_t newStartFrame) |
1068 { | 1107 { |
1069 if (!m_model) return; | 1108 auto model = ModelById::getAs<NoteModel>(m_model); |
1109 if (!model) return; | |
1070 | 1110 |
1071 ChangeEventsCommand *command = | 1111 ChangeEventsCommand *command = |
1072 new ChangeEventsCommand(m_model, tr("Drag Selection")); | 1112 new ChangeEventsCommand(m_model.untyped, tr("Drag Selection")); |
1073 | 1113 |
1074 EventVector points = | 1114 EventVector points = |
1075 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); | 1115 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
1076 | 1116 |
1077 for (Event p: points) { | 1117 for (Event p: points) { |
1078 command->remove(p); | 1118 command->remove(p); |
1079 Event moved = p.withFrame(p.getFrame() + | 1119 Event moved = p.withFrame(p.getFrame() + |
1080 newStartFrame - s.getStartFrame()); | 1120 newStartFrame - s.getStartFrame()); |
1085 } | 1125 } |
1086 | 1126 |
1087 void | 1127 void |
1088 NoteLayer::resizeSelection(Selection s, Selection newSize) | 1128 NoteLayer::resizeSelection(Selection s, Selection newSize) |
1089 { | 1129 { |
1090 if (!m_model || !s.getDuration()) return; | 1130 auto model = ModelById::getAs<NoteModel>(m_model); |
1131 if (!model || !s.getDuration()) return; | |
1091 | 1132 |
1092 ChangeEventsCommand *command = | 1133 ChangeEventsCommand *command = |
1093 new ChangeEventsCommand(m_model, tr("Resize Selection")); | 1134 new ChangeEventsCommand(m_model.untyped, tr("Resize Selection")); |
1094 | 1135 |
1095 EventVector points = | 1136 EventVector points = |
1096 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); | 1137 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
1097 | 1138 |
1098 double ratio = double(newSize.getDuration()) / double(s.getDuration()); | 1139 double ratio = double(newSize.getDuration()) / double(s.getDuration()); |
1099 double oldStart = double(s.getStartFrame()); | 1140 double oldStart = double(s.getStartFrame()); |
1100 double newStart = double(newSize.getStartFrame()); | 1141 double newStart = double(newSize.getStartFrame()); |
1101 | 1142 |
1115 } | 1156 } |
1116 | 1157 |
1117 void | 1158 void |
1118 NoteLayer::deleteSelection(Selection s) | 1159 NoteLayer::deleteSelection(Selection s) |
1119 { | 1160 { |
1120 if (!m_model) return; | 1161 auto model = ModelById::getAs<NoteModel>(m_model); |
1162 if (!model) return; | |
1121 | 1163 |
1122 ChangeEventsCommand *command = | 1164 ChangeEventsCommand *command = |
1123 new ChangeEventsCommand(m_model, tr("Delete Selected Points")); | 1165 new ChangeEventsCommand(m_model.untyped, tr("Delete Selected Points")); |
1124 | 1166 |
1125 EventVector points = | 1167 EventVector points = |
1126 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); | 1168 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
1127 | 1169 |
1128 for (Event p: points) { | 1170 for (Event p: points) { |
1129 command->remove(p); | 1171 command->remove(p); |
1130 } | 1172 } |
1131 | 1173 |
1133 } | 1175 } |
1134 | 1176 |
1135 void | 1177 void |
1136 NoteLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) | 1178 NoteLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) |
1137 { | 1179 { |
1138 if (!m_model) return; | 1180 auto model = ModelById::getAs<NoteModel>(m_model); |
1181 if (!model) return; | |
1139 | 1182 |
1140 EventVector points = | 1183 EventVector points = |
1141 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); | 1184 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
1142 | 1185 |
1143 for (Event p: points) { | 1186 for (Event p: points) { |
1144 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); | 1187 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); |
1145 } | 1188 } |
1146 } | 1189 } |
1147 | 1190 |
1148 bool | 1191 bool |
1149 NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, | 1192 NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, |
1150 sv_frame_t /* frameOffset */, bool /* interactive */) | 1193 sv_frame_t /* frameOffset */, bool /* interactive */) |
1151 { | 1194 { |
1152 if (!m_model) return false; | 1195 auto model = ModelById::getAs<NoteModel>(m_model); |
1196 if (!model) return false; | |
1153 | 1197 |
1154 const EventVector &points = from.getPoints(); | 1198 const EventVector &points = from.getPoints(); |
1155 | 1199 |
1156 bool realign = false; | 1200 bool realign = false; |
1157 | 1201 |
1171 realign = true; | 1215 realign = true; |
1172 } | 1216 } |
1173 } | 1217 } |
1174 | 1218 |
1175 ChangeEventsCommand *command = | 1219 ChangeEventsCommand *command = |
1176 new ChangeEventsCommand(m_model, tr("Paste")); | 1220 new ChangeEventsCommand(m_model.untyped, tr("Paste")); |
1177 | 1221 |
1178 for (EventVector::const_iterator i = points.begin(); | 1222 for (EventVector::const_iterator i = points.begin(); |
1179 i != points.end(); ++i) { | 1223 i != points.end(); ++i) { |
1180 | 1224 |
1181 sv_frame_t frame = 0; | 1225 sv_frame_t frame = 0; |
1195 } | 1239 } |
1196 | 1240 |
1197 Event p = *i; | 1241 Event p = *i; |
1198 Event newPoint = p; | 1242 Event newPoint = p; |
1199 if (!p.hasValue()) { | 1243 if (!p.hasValue()) { |
1200 newPoint = newPoint.withValue((m_model->getValueMinimum() + | 1244 newPoint = newPoint.withValue((model->getValueMinimum() + |
1201 m_model->getValueMaximum()) / 2); | 1245 model->getValueMaximum()) / 2); |
1202 } | 1246 } |
1203 if (!p.hasDuration()) { | 1247 if (!p.hasDuration()) { |
1204 sv_frame_t nextFrame = frame; | 1248 sv_frame_t nextFrame = frame; |
1205 EventVector::const_iterator j = i; | 1249 EventVector::const_iterator j = i; |
1206 for (; j != points.end(); ++j) { | 1250 for (; j != points.end(); ++j) { |
1208 } | 1252 } |
1209 if (j != points.end()) { | 1253 if (j != points.end()) { |
1210 nextFrame = j->getFrame(); | 1254 nextFrame = j->getFrame(); |
1211 } | 1255 } |
1212 if (nextFrame == frame) { | 1256 if (nextFrame == frame) { |
1213 newPoint = newPoint.withDuration(m_model->getResolution()); | 1257 newPoint = newPoint.withDuration(model->getResolution()); |
1214 } else { | 1258 } else { |
1215 newPoint = newPoint.withDuration(nextFrame - frame); | 1259 newPoint = newPoint.withDuration(nextFrame - frame); |
1216 } | 1260 } |
1217 } | 1261 } |
1218 | 1262 |
1231 } | 1275 } |
1232 | 1276 |
1233 void | 1277 void |
1234 NoteLayer::addNoteOff(sv_frame_t frame, int pitch) | 1278 NoteLayer::addNoteOff(sv_frame_t frame, int pitch) |
1235 { | 1279 { |
1280 auto model = ModelById::getAs<NoteModel>(m_model); | |
1281 | |
1236 for (NoteSet::iterator i = m_pendingNoteOns.begin(); | 1282 for (NoteSet::iterator i = m_pendingNoteOns.begin(); |
1237 i != m_pendingNoteOns.end(); ++i) { | 1283 i != m_pendingNoteOns.end(); ++i) { |
1238 | 1284 |
1239 Event p = *i; | 1285 Event p = *i; |
1240 | 1286 |
1241 if (lrintf(p.getValue()) == pitch) { | 1287 if (lrintf(p.getValue()) == pitch) { |
1242 m_pendingNoteOns.erase(i); | 1288 m_pendingNoteOns.erase(i); |
1243 Event note = p.withDuration(frame - p.getFrame()); | 1289 Event note = p.withDuration(frame - p.getFrame()); |
1244 if (m_model) { | 1290 if (model) { |
1245 ChangeEventsCommand *c = new ChangeEventsCommand | 1291 ChangeEventsCommand *c = new ChangeEventsCommand |
1246 (m_model, tr("Record Note")); | 1292 (m_model.untyped, tr("Record Note")); |
1247 c->add(note); | 1293 c->add(note); |
1248 // execute and bundle: | 1294 // execute and bundle: |
1249 CommandHistory::getInstance()->addCommand(c, true, true); | 1295 CommandHistory::getInstance()->addCommand(c, true, true); |
1250 } | 1296 } |
1251 break; | 1297 break; |