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; |
