Mercurial > hg > svgui
comparison layer/NoteLayer.cpp @ 1459:42c87368287c
Merge from branch single-point
author | Chris Cannam |
---|---|
date | Fri, 17 May 2019 10:02:52 +0100 |
parents | 5b9692768beb |
children | 696e569ff21b |
comparison
equal
deleted
inserted
replaced
1441:8d5bf4ab98ef | 1459:42c87368287c |
---|---|
388 } | 388 } |
389 | 389 |
390 return mapper; | 390 return mapper; |
391 } | 391 } |
392 | 392 |
393 NoteModel::PointList | 393 EventVector |
394 NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const | 394 NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const |
395 { | 395 { |
396 if (!m_model) return NoteModel::PointList(); | 396 if (!m_model) return {}; |
397 | 397 |
398 sv_frame_t frame = v->getFrameForX(x); | 398 sv_frame_t frame = v->getFrameForX(x); |
399 | 399 |
400 NoteModel::PointList onPoints = | 400 EventVector local = m_model->getEventsCovering(frame); |
401 m_model->getPoints(frame); | 401 if (!local.empty()) return local; |
402 | 402 |
403 if (!onPoints.empty()) { | 403 int fuzz = ViewManager::scalePixelSize(2); |
404 return onPoints; | 404 sv_frame_t start = v->getFrameForX(x - fuzz); |
405 } | 405 sv_frame_t end = v->getFrameForX(x + fuzz); |
406 | 406 |
407 NoteModel::PointList prevPoints = | 407 local = m_model->getEventsStartingWithin(frame, end - frame); |
408 m_model->getPreviousPoints(frame); | 408 if (!local.empty()) return local; |
409 NoteModel::PointList nextPoints = | 409 |
410 m_model->getNextPoints(frame); | 410 local = m_model->getEventsSpanning(start, frame - start); |
411 | 411 if (!local.empty()) return local; |
412 NoteModel::PointList usePoints = prevPoints; | 412 |
413 | 413 return {}; |
414 if (prevPoints.empty()) { | |
415 usePoints = nextPoints; | |
416 } else if (int(prevPoints.begin()->frame) < v->getStartFrame() && | |
417 !(nextPoints.begin()->frame > v->getEndFrame())) { | |
418 usePoints = nextPoints; | |
419 } else if (int(nextPoints.begin()->frame) - frame < | |
420 frame - int(prevPoints.begin()->frame)) { | |
421 usePoints = nextPoints; | |
422 } | |
423 | |
424 if (!usePoints.empty()) { | |
425 int fuzz = ViewManager::scalePixelSize(2); | |
426 int px = v->getXForFrame(usePoints.begin()->frame); | |
427 if ((px > x && px - x > fuzz) || | |
428 (px < x && x - px > fuzz + 1)) { | |
429 usePoints.clear(); | |
430 } | |
431 } | |
432 | |
433 return usePoints; | |
434 } | 414 } |
435 | 415 |
436 bool | 416 bool |
437 NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, NoteModel::Point &p) const | 417 NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &point) const |
438 { | 418 { |
439 if (!m_model) return false; | 419 if (!m_model) return false; |
440 | 420 |
441 sv_frame_t frame = v->getFrameForX(x); | 421 sv_frame_t frame = v->getFrameForX(x); |
442 | 422 |
443 NoteModel::PointList onPoints = m_model->getPoints(frame); | 423 EventVector onPoints = m_model->getEventsCovering(frame); |
444 if (onPoints.empty()) return false; | 424 if (onPoints.empty()) return false; |
445 | 425 |
446 // cerr << "frame " << frame << ": " << onPoints.size() << " candidate points" << endl; | |
447 | |
448 int nearestDistance = -1; | 426 int nearestDistance = -1; |
449 | 427 for (const auto &p: onPoints) { |
450 for (NoteModel::PointList::const_iterator i = onPoints.begin(); | 428 int distance = getYForValue(v, p.getValue()) - y; |
451 i != onPoints.end(); ++i) { | |
452 | |
453 int distance = getYForValue(v, (*i).value) - y; | |
454 if (distance < 0) distance = -distance; | 429 if (distance < 0) distance = -distance; |
455 if (nearestDistance == -1 || distance < nearestDistance) { | 430 if (nearestDistance == -1 || distance < nearestDistance) { |
456 nearestDistance = distance; | 431 nearestDistance = distance; |
457 p = *i; | 432 point = p; |
458 } | 433 } |
459 } | 434 } |
460 | 435 |
461 return true; | 436 return true; |
462 } | 437 } |
466 { | 441 { |
467 int x = pos.x(); | 442 int x = pos.x(); |
468 | 443 |
469 if (!m_model || !m_model->getSampleRate()) return ""; | 444 if (!m_model || !m_model->getSampleRate()) return ""; |
470 | 445 |
471 NoteModel::PointList points = getLocalPoints(v, x); | 446 EventVector points = getLocalPoints(v, x); |
472 | 447 |
473 if (points.empty()) { | 448 if (points.empty()) { |
474 if (!m_model->isReady()) { | 449 if (!m_model->isReady()) { |
475 return tr("In progress"); | 450 return tr("In progress"); |
476 } else { | 451 } else { |
477 return tr("No local points"); | 452 return tr("No local points"); |
478 } | 453 } |
479 } | 454 } |
480 | 455 |
481 Note note(0); | 456 Event note; |
482 NoteModel::PointList::iterator i; | 457 EventVector::iterator i; |
483 | 458 |
484 for (i = points.begin(); i != points.end(); ++i) { | 459 for (i = points.begin(); i != points.end(); ++i) { |
485 | 460 |
486 int y = getYForValue(v, i->value); | 461 int y = getYForValue(v, i->getValue()); |
487 int h = 3; | 462 int h = 3; |
488 | 463 |
489 if (m_model->getValueQuantization() != 0.0) { | 464 if (m_model->getValueQuantization() != 0.0) { |
490 h = y - getYForValue(v, i->value + m_model->getValueQuantization()); | 465 h = y - getYForValue |
466 (v, i->getValue() + m_model->getValueQuantization()); | |
491 if (h < 3) h = 3; | 467 if (h < 3) h = 3; |
492 } | 468 } |
493 | 469 |
494 if (pos.y() >= y - h && pos.y() <= y) { | 470 if (pos.y() >= y - h && pos.y() <= y) { |
495 note = *i; | 471 note = *i; |
497 } | 473 } |
498 } | 474 } |
499 | 475 |
500 if (i == points.end()) return tr("No local points"); | 476 if (i == points.end()) return tr("No local points"); |
501 | 477 |
502 RealTime rt = RealTime::frame2RealTime(note.frame, | 478 RealTime rt = RealTime::frame2RealTime(note.getFrame(), |
503 m_model->getSampleRate()); | 479 m_model->getSampleRate()); |
504 RealTime rd = RealTime::frame2RealTime(note.duration, | 480 RealTime rd = RealTime::frame2RealTime(note.getDuration(), |
505 m_model->getSampleRate()); | 481 m_model->getSampleRate()); |
506 | 482 |
507 QString pitchText; | 483 QString pitchText; |
508 | 484 |
485 float value = note.getValue(); | |
486 | |
509 if (shouldConvertMIDIToHz()) { | 487 if (shouldConvertMIDIToHz()) { |
510 | 488 |
511 int mnote = int(lrint(note.value)); | 489 int mnote = int(lrint(value)); |
512 int cents = int(lrint((note.value - float(mnote)) * 100)); | 490 int cents = int(lrint((value - float(mnote)) * 100)); |
513 double freq = Pitch::getFrequencyForPitch(mnote, cents); | 491 double freq = Pitch::getFrequencyForPitch(mnote, cents); |
514 pitchText = tr("%1 (%2, %3 Hz)") | 492 pitchText = tr("%1 (%2, %3 Hz)") |
515 .arg(Pitch::getPitchLabel(mnote, cents)) | 493 .arg(Pitch::getPitchLabel(mnote, cents)) |
516 .arg(mnote) | 494 .arg(mnote) |
517 .arg(freq); | 495 .arg(freq); |
518 | 496 |
519 } else if (getScaleUnits() == "Hz") { | 497 } else if (getScaleUnits() == "Hz") { |
520 | 498 |
521 pitchText = tr("%1 Hz (%2, %3)") | 499 pitchText = tr("%1 Hz (%2, %3)") |
522 .arg(note.value) | 500 .arg(value) |
523 .arg(Pitch::getPitchLabelForFrequency(note.value)) | 501 .arg(Pitch::getPitchLabelForFrequency(value)) |
524 .arg(Pitch::getPitchForFrequency(note.value)); | 502 .arg(Pitch::getPitchForFrequency(value)); |
525 | 503 |
526 } else { | 504 } else { |
527 pitchText = tr("%1 %2") | 505 pitchText = tr("%1 %2") |
528 .arg(note.value).arg(getScaleUnits()); | 506 .arg(value).arg(getScaleUnits()); |
529 } | 507 } |
530 | 508 |
531 QString text; | 509 QString text; |
532 | 510 |
533 if (note.label == "") { | 511 if (note.getLabel() == "") { |
534 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label")) | 512 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label")) |
535 .arg(rt.toText(true).c_str()) | 513 .arg(rt.toText(true).c_str()) |
536 .arg(pitchText) | 514 .arg(pitchText) |
537 .arg(rd.toText(true).c_str()); | 515 .arg(rd.toText(true).c_str()); |
538 } else { | 516 } else { |
539 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4")) | 517 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4")) |
540 .arg(rt.toText(true).c_str()) | 518 .arg(rt.toText(true).c_str()) |
541 .arg(pitchText) | 519 .arg(pitchText) |
542 .arg(rd.toText(true).c_str()) | 520 .arg(rd.toText(true).c_str()) |
543 .arg(note.label); | 521 .arg(note.getLabel()); |
544 } | 522 } |
545 | 523 |
546 pos = QPoint(v->getXForFrame(note.frame), | 524 pos = QPoint(v->getXForFrame(note.getFrame()), getYForValue(v, value)); |
547 getYForValue(v, note.value)); | |
548 return text; | 525 return text; |
549 } | 526 } |
550 | 527 |
551 bool | 528 bool |
552 NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, | 529 NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, |
555 { | 532 { |
556 if (!m_model) { | 533 if (!m_model) { |
557 return Layer::snapToFeatureFrame(v, frame, resolution, snap); | 534 return Layer::snapToFeatureFrame(v, frame, resolution, snap); |
558 } | 535 } |
559 | 536 |
537 // SnapLeft / SnapRight: return frame of nearest feature in that | |
538 // direction no matter how far away | |
539 // | |
540 // SnapNeighbouring: return frame of feature that would be used in | |
541 // an editing operation, i.e. closest feature in either direction | |
542 // but only if it is "close enough" | |
543 | |
560 resolution = m_model->getResolution(); | 544 resolution = m_model->getResolution(); |
561 NoteModel::PointList points; | |
562 | 545 |
563 if (snap == SnapNeighbouring) { | 546 if (snap == SnapNeighbouring) { |
564 | 547 EventVector points = getLocalPoints(v, v->getXForFrame(frame)); |
565 points = getLocalPoints(v, v->getXForFrame(frame)); | |
566 if (points.empty()) return false; | 548 if (points.empty()) return false; |
567 frame = points.begin()->frame; | 549 frame = points.begin()->getFrame(); |
568 return true; | 550 return true; |
569 } | 551 } |
570 | 552 |
571 points = m_model->getPoints(frame, frame); | 553 Event e; |
572 sv_frame_t snapped = frame; | 554 if (m_model->getNearestEventMatching |
573 bool found = false; | 555 (frame, |
574 | 556 [](Event) { return true; }, |
575 for (NoteModel::PointList::const_iterator i = points.begin(); | 557 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, |
576 i != points.end(); ++i) { | 558 e)) { |
577 | 559 frame = e.getFrame(); |
578 if (snap == SnapRight) { | 560 return true; |
579 | 561 } |
580 if (i->frame > frame) { | 562 |
581 snapped = i->frame; | 563 return false; |
582 found = true; | |
583 break; | |
584 } | |
585 | |
586 } else if (snap == SnapLeft) { | |
587 | |
588 if (i->frame <= frame) { | |
589 snapped = i->frame; | |
590 found = true; // don't break, as the next may be better | |
591 } else { | |
592 break; | |
593 } | |
594 | |
595 } else { // nearest | |
596 | |
597 NoteModel::PointList::const_iterator j = i; | |
598 ++j; | |
599 | |
600 if (j == points.end()) { | |
601 | |
602 snapped = i->frame; | |
603 found = true; | |
604 break; | |
605 | |
606 } else if (j->frame >= frame) { | |
607 | |
608 if (j->frame - frame < frame - i->frame) { | |
609 snapped = j->frame; | |
610 } else { | |
611 snapped = i->frame; | |
612 } | |
613 found = true; | |
614 break; | |
615 } | |
616 } | |
617 } | |
618 | |
619 frame = snapped; | |
620 return found; | |
621 } | 564 } |
622 | 565 |
623 void | 566 void |
624 NoteLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, bool &log) const | 567 NoteLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, bool &log) const |
625 { | 568 { |
754 | 697 |
755 int x0 = rect.left(), x1 = rect.right(); | 698 int x0 = rect.left(), x1 = rect.right(); |
756 sv_frame_t frame0 = v->getFrameForX(x0); | 699 sv_frame_t frame0 = v->getFrameForX(x0); |
757 sv_frame_t frame1 = v->getFrameForX(x1); | 700 sv_frame_t frame1 = v->getFrameForX(x1); |
758 | 701 |
759 NoteModel::PointList points(m_model->getPoints(frame0, frame1)); | 702 EventVector points(m_model->getEventsSpanning(frame0, frame1 - frame0)); |
760 if (points.empty()) return; | 703 if (points.empty()) return; |
761 | 704 |
762 paint.setPen(getBaseQColor()); | 705 paint.setPen(getBaseQColor()); |
763 | 706 |
764 QColor brushColour(getBaseQColor()); | 707 QColor brushColour(getBaseQColor()); |
770 double min = m_model->getValueMinimum(); | 713 double min = m_model->getValueMinimum(); |
771 double max = m_model->getValueMaximum(); | 714 double max = m_model->getValueMaximum(); |
772 if (max == min) max = min + 1.0; | 715 if (max == min) max = min + 1.0; |
773 | 716 |
774 QPoint localPos; | 717 QPoint localPos; |
775 NoteModel::Point illuminatePoint(0); | 718 Event illuminatePoint; |
776 bool shouldIlluminate = false; | 719 bool shouldIlluminate = false; |
777 | 720 |
778 if (v->shouldIlluminateLocalFeatures(this, localPos)) { | 721 if (v->shouldIlluminateLocalFeatures(this, localPos)) { |
779 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(), | 722 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(), |
780 illuminatePoint); | 723 illuminatePoint); |
784 } | 727 } |
785 | 728 |
786 paint.save(); | 729 paint.save(); |
787 paint.setRenderHint(QPainter::Antialiasing, false); | 730 paint.setRenderHint(QPainter::Antialiasing, false); |
788 | 731 |
789 for (NoteModel::PointList::const_iterator i = points.begin(); | 732 for (EventVector::const_iterator i = points.begin(); |
790 i != points.end(); ++i) { | 733 i != points.end(); ++i) { |
791 | 734 |
792 const NoteModel::Point &p(*i); | 735 const Event &p(*i); |
793 | 736 |
794 int x = v->getXForFrame(p.frame); | 737 int x = v->getXForFrame(p.getFrame()); |
795 int y = getYForValue(v, p.value); | 738 int y = getYForValue(v, p.getValue()); |
796 int w = v->getXForFrame(p.frame + p.duration) - x; | 739 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x; |
797 int h = 3; | 740 int h = 3; |
798 | 741 |
799 if (m_model->getValueQuantization() != 0.0) { | 742 if (m_model->getValueQuantization() != 0.0) { |
800 h = y - getYForValue(v, p.value + m_model->getValueQuantization()); | 743 h = y - getYForValue(v, p.getValue() + m_model->getValueQuantization()); |
801 if (h < 3) h = 3; | 744 if (h < 3) h = 3; |
802 } | 745 } |
803 | 746 |
804 if (w < 1) w = 1; | 747 if (w < 1) w = 1; |
805 paint.setPen(getBaseQColor()); | 748 paint.setPen(getBaseQColor()); |
806 paint.setBrush(brushColour); | 749 paint.setBrush(brushColour); |
807 | 750 |
808 if (shouldIlluminate && | 751 if (shouldIlluminate && illuminatePoint == p) { |
809 // "illuminatePoint == p" | |
810 !NoteModel::Point::Comparator()(illuminatePoint, p) && | |
811 !NoteModel::Point::Comparator()(p, illuminatePoint)) { | |
812 | 752 |
813 paint.setPen(v->getForeground()); | 753 paint.setPen(v->getForeground()); |
814 paint.setBrush(v->getForeground()); | 754 paint.setBrush(v->getForeground()); |
815 | 755 |
816 QString vlabel = QString("%1%2").arg(p.value).arg(getScaleUnits()); | 756 QString vlabel = QString("%1%2").arg(p.getValue()).arg(getScaleUnits()); |
817 PaintAssistant::drawVisibleText(v, paint, | 757 PaintAssistant::drawVisibleText(v, paint, |
818 x - paint.fontMetrics().width(vlabel) - 2, | 758 x - paint.fontMetrics().width(vlabel) - 2, |
819 y + paint.fontMetrics().height()/2 | 759 y + paint.fontMetrics().height()/2 |
820 - paint.fontMetrics().descent(), | 760 - paint.fontMetrics().descent(), |
821 vlabel, PaintAssistant::OutlinedText); | 761 vlabel, PaintAssistant::OutlinedText); |
822 | 762 |
823 QString hlabel = RealTime::frame2RealTime | 763 QString hlabel = RealTime::frame2RealTime |
824 (p.frame, m_model->getSampleRate()).toText(true).c_str(); | 764 (p.getFrame(), m_model->getSampleRate()).toText(true).c_str(); |
825 PaintAssistant::drawVisibleText(v, paint, | 765 PaintAssistant::drawVisibleText(v, paint, |
826 x, | 766 x, |
827 y - h/2 - paint.fontMetrics().descent() - 2, | 767 y - h/2 - paint.fontMetrics().descent() - 2, |
828 hlabel, PaintAssistant::OutlinedText); | 768 hlabel, PaintAssistant::OutlinedText); |
829 } | 769 } |
853 } | 793 } |
854 | 794 |
855 void | 795 void |
856 NoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const | 796 NoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const |
857 { | 797 { |
858 if (!m_model || m_model->getPoints().empty()) return; | 798 if (!m_model || m_model->isEmpty()) return; |
859 | 799 |
860 QString unit; | 800 QString unit; |
861 double min, max; | 801 double min, max; |
862 bool logarithmic; | 802 bool logarithmic; |
863 | 803 |
901 if (frame < 0) frame = 0; | 841 if (frame < 0) frame = 0; |
902 frame = frame / m_model->getResolution() * m_model->getResolution(); | 842 frame = frame / m_model->getResolution() * m_model->getResolution(); |
903 | 843 |
904 double value = getValueForY(v, e->y()); | 844 double value = getValueForY(v, e->y()); |
905 | 845 |
906 m_editingPoint = NoteModel::Point(frame, float(value), 0, 0.8f, tr("New Point")); | 846 m_editingPoint = Event(frame, float(value), 0, 0.8f, tr("New Point")); |
907 m_originalPoint = m_editingPoint; | 847 m_originalPoint = m_editingPoint; |
908 | 848 |
909 if (m_editingCommand) finish(m_editingCommand); | 849 if (m_editingCommand) finish(m_editingCommand); |
910 m_editingCommand = new NoteModel::EditCommand(m_model, | 850 m_editingCommand = new ChangeEventsCommand(m_model, tr("Draw Point")); |
911 tr("Draw Point")); | 851 m_editingCommand->add(m_editingPoint); |
912 m_editingCommand->addPoint(m_editingPoint); | |
913 | 852 |
914 m_editing = true; | 853 m_editing = true; |
915 } | 854 } |
916 | 855 |
917 void | 856 void |
925 if (frame < 0) frame = 0; | 864 if (frame < 0) frame = 0; |
926 frame = frame / m_model->getResolution() * m_model->getResolution(); | 865 frame = frame / m_model->getResolution() * m_model->getResolution(); |
927 | 866 |
928 double newValue = getValueForY(v, e->y()); | 867 double newValue = getValueForY(v, e->y()); |
929 | 868 |
930 sv_frame_t newFrame = m_editingPoint.frame; | 869 sv_frame_t newFrame = m_editingPoint.getFrame(); |
931 sv_frame_t newDuration = frame - newFrame; | 870 sv_frame_t newDuration = frame - newFrame; |
932 if (newDuration < 0) { | 871 if (newDuration < 0) { |
933 newFrame = frame; | 872 newFrame = frame; |
934 newDuration = -newDuration; | 873 newDuration = -newDuration; |
935 } else if (newDuration == 0) { | 874 } else if (newDuration == 0) { |
936 newDuration = 1; | 875 newDuration = 1; |
937 } | 876 } |
938 | 877 |
939 m_editingCommand->deletePoint(m_editingPoint); | 878 m_editingCommand->remove(m_editingPoint); |
940 m_editingPoint.frame = newFrame; | 879 m_editingPoint = m_editingPoint |
941 m_editingPoint.value = float(newValue); | 880 .withFrame(newFrame) |
942 m_editingPoint.duration = newDuration; | 881 .withValue(float(newValue)) |
943 m_editingCommand->addPoint(m_editingPoint); | 882 .withDuration(newDuration); |
883 m_editingCommand->add(m_editingPoint); | |
944 } | 884 } |
945 | 885 |
946 void | 886 void |
947 NoteLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) | 887 NoteLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) |
948 { | 888 { |
978 { | 918 { |
979 if (!m_model || !m_editing) return; | 919 if (!m_model || !m_editing) return; |
980 | 920 |
981 m_editing = false; | 921 m_editing = false; |
982 | 922 |
983 NoteModel::Point p(0); | 923 Event p(0); |
984 if (!getPointToDrag(v, e->x(), e->y(), p)) return; | 924 if (!getPointToDrag(v, e->x(), e->y(), p)) return; |
985 if (p.frame != m_editingPoint.frame || p.value != m_editingPoint.value) return; | 925 if (p.getFrame() != m_editingPoint.getFrame() || |
986 | 926 p.getValue() != m_editingPoint.getValue()) return; |
987 m_editingCommand = new NoteModel::EditCommand(m_model, tr("Erase Point")); | 927 |
988 | 928 m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point")); |
989 m_editingCommand->deletePoint(m_editingPoint); | 929 |
930 m_editingCommand->remove(m_editingPoint); | |
990 | 931 |
991 finish(m_editingCommand); | 932 finish(m_editingCommand); |
992 m_editingCommand = nullptr; | 933 m_editingCommand = nullptr; |
993 m_editing = false; | 934 m_editing = false; |
994 } | 935 } |
1001 if (!m_model) return; | 942 if (!m_model) return; |
1002 | 943 |
1003 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; | 944 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; |
1004 m_originalPoint = m_editingPoint; | 945 m_originalPoint = m_editingPoint; |
1005 | 946 |
1006 m_dragPointX = v->getXForFrame(m_editingPoint.frame); | 947 m_dragPointX = v->getXForFrame(m_editingPoint.getFrame()); |
1007 m_dragPointY = getYForValue(v, m_editingPoint.value); | 948 m_dragPointY = getYForValue(v, m_editingPoint.getValue()); |
1008 | 949 |
1009 if (m_editingCommand) { | 950 if (m_editingCommand) { |
1010 finish(m_editingCommand); | 951 finish(m_editingCommand); |
1011 m_editingCommand = nullptr; | 952 m_editingCommand = nullptr; |
1012 } | 953 } |
1033 frame = frame / m_model->getResolution() * m_model->getResolution(); | 974 frame = frame / m_model->getResolution() * m_model->getResolution(); |
1034 | 975 |
1035 double value = getValueForY(v, newy); | 976 double value = getValueForY(v, newy); |
1036 | 977 |
1037 if (!m_editingCommand) { | 978 if (!m_editingCommand) { |
1038 m_editingCommand = new NoteModel::EditCommand(m_model, | 979 m_editingCommand = new ChangeEventsCommand(m_model, |
1039 tr("Drag Point")); | 980 tr("Drag Point")); |
1040 } | 981 } |
1041 | 982 |
1042 m_editingCommand->deletePoint(m_editingPoint); | 983 m_editingCommand->remove(m_editingPoint); |
1043 m_editingPoint.frame = frame; | 984 m_editingPoint = m_editingPoint |
1044 m_editingPoint.value = float(value); | 985 .withFrame(frame) |
1045 m_editingCommand->addPoint(m_editingPoint); | 986 .withValue(float(value)); |
987 m_editingCommand->add(m_editingPoint); | |
1046 } | 988 } |
1047 | 989 |
1048 void | 990 void |
1049 NoteLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) | 991 NoteLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) |
1050 { | 992 { |
1053 | 995 |
1054 if (m_editingCommand) { | 996 if (m_editingCommand) { |
1055 | 997 |
1056 QString newName = m_editingCommand->getName(); | 998 QString newName = m_editingCommand->getName(); |
1057 | 999 |
1058 if (m_editingPoint.frame != m_originalPoint.frame) { | 1000 if (m_editingPoint.getFrame() != m_originalPoint.getFrame()) { |
1059 if (m_editingPoint.value != m_originalPoint.value) { | 1001 if (m_editingPoint.getValue() != m_originalPoint.getValue()) { |
1060 newName = tr("Edit Point"); | 1002 newName = tr("Edit Point"); |
1061 } else { | 1003 } else { |
1062 newName = tr("Relocate Point"); | 1004 newName = tr("Relocate Point"); |
1063 } | 1005 } |
1064 } else { | 1006 } else { |
1076 bool | 1018 bool |
1077 NoteLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) | 1019 NoteLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) |
1078 { | 1020 { |
1079 if (!m_model) return false; | 1021 if (!m_model) return false; |
1080 | 1022 |
1081 NoteModel::Point note(0); | 1023 Event note(0); |
1082 if (!getPointToDrag(v, e->x(), e->y(), note)) return false; | 1024 if (!getPointToDrag(v, e->x(), e->y(), note)) return false; |
1083 | 1025 |
1084 // NoteModel::Point note = *points.begin(); | 1026 // Event note = *points.begin(); |
1085 | 1027 |
1086 ItemEditDialog *dialog = new ItemEditDialog | 1028 ItemEditDialog *dialog = new ItemEditDialog |
1087 (m_model->getSampleRate(), | 1029 (m_model->getSampleRate(), |
1088 ItemEditDialog::ShowTime | | 1030 ItemEditDialog::ShowTime | |
1089 ItemEditDialog::ShowDuration | | 1031 ItemEditDialog::ShowDuration | |
1090 ItemEditDialog::ShowValue | | 1032 ItemEditDialog::ShowValue | |
1091 ItemEditDialog::ShowText, | 1033 ItemEditDialog::ShowText, |
1092 getScaleUnits()); | 1034 getScaleUnits()); |
1093 | 1035 |
1094 dialog->setFrameTime(note.frame); | 1036 dialog->setFrameTime(note.getFrame()); |
1095 dialog->setValue(note.value); | 1037 dialog->setValue(note.getValue()); |
1096 dialog->setFrameDuration(note.duration); | 1038 dialog->setFrameDuration(note.getDuration()); |
1097 dialog->setText(note.label); | 1039 dialog->setText(note.getLabel()); |
1098 | 1040 |
1099 m_editingPoint = note; | 1041 m_editingPoint = note; |
1100 m_editIsOpen = true; | 1042 m_editIsOpen = true; |
1101 | 1043 |
1102 if (dialog->exec() == QDialog::Accepted) { | 1044 if (dialog->exec() == QDialog::Accepted) { |
1103 | 1045 |
1104 NoteModel::Point newNote = note; | 1046 Event newNote = note |
1105 newNote.frame = dialog->getFrameTime(); | 1047 .withFrame(dialog->getFrameTime()) |
1106 newNote.value = dialog->getValue(); | 1048 .withValue(dialog->getValue()) |
1107 newNote.duration = dialog->getFrameDuration(); | 1049 .withDuration(dialog->getFrameDuration()) |
1108 newNote.label = dialog->getText(); | 1050 .withLabel(dialog->getText()); |
1109 | 1051 |
1110 NoteModel::EditCommand *command = new NoteModel::EditCommand | 1052 ChangeEventsCommand *command = new ChangeEventsCommand |
1111 (m_model, tr("Edit Point")); | 1053 (m_model, tr("Edit Point")); |
1112 command->deletePoint(note); | 1054 command->remove(note); |
1113 command->addPoint(newNote); | 1055 command->add(newNote); |
1114 finish(command); | 1056 finish(command); |
1115 } | 1057 } |
1116 | 1058 |
1117 m_editingPoint = 0; | 1059 m_editingPoint = 0; |
1118 m_editIsOpen = false; | 1060 m_editIsOpen = false; |
1124 void | 1066 void |
1125 NoteLayer::moveSelection(Selection s, sv_frame_t newStartFrame) | 1067 NoteLayer::moveSelection(Selection s, sv_frame_t newStartFrame) |
1126 { | 1068 { |
1127 if (!m_model) return; | 1069 if (!m_model) return; |
1128 | 1070 |
1129 NoteModel::EditCommand *command = | 1071 ChangeEventsCommand *command = |
1130 new NoteModel::EditCommand(m_model, tr("Drag Selection")); | 1072 new ChangeEventsCommand(m_model, tr("Drag Selection")); |
1131 | 1073 |
1132 NoteModel::PointList points = | 1074 EventVector points = |
1133 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | 1075 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
1134 | 1076 |
1135 for (NoteModel::PointList::iterator i = points.begin(); | 1077 for (Event p: points) { |
1136 i != points.end(); ++i) { | 1078 command->remove(p); |
1137 | 1079 Event moved = p.withFrame(p.getFrame() + |
1138 if (s.contains(i->frame)) { | 1080 newStartFrame - s.getStartFrame()); |
1139 NoteModel::Point newPoint(*i); | 1081 command->add(moved); |
1140 newPoint.frame = i->frame + newStartFrame - s.getStartFrame(); | |
1141 command->deletePoint(*i); | |
1142 command->addPoint(newPoint); | |
1143 } | |
1144 } | 1082 } |
1145 | 1083 |
1146 finish(command); | 1084 finish(command); |
1147 } | 1085 } |
1148 | 1086 |
1149 void | 1087 void |
1150 NoteLayer::resizeSelection(Selection s, Selection newSize) | 1088 NoteLayer::resizeSelection(Selection s, Selection newSize) |
1151 { | 1089 { |
1090 if (!m_model || !s.getDuration()) return; | |
1091 | |
1092 ChangeEventsCommand *command = | |
1093 new ChangeEventsCommand(m_model, tr("Resize Selection")); | |
1094 | |
1095 EventVector points = | |
1096 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); | |
1097 | |
1098 double ratio = double(newSize.getDuration()) / double(s.getDuration()); | |
1099 double oldStart = double(s.getStartFrame()); | |
1100 double newStart = double(newSize.getStartFrame()); | |
1101 | |
1102 for (Event p: points) { | |
1103 | |
1104 double newFrame = (double(p.getFrame()) - oldStart) * ratio + newStart; | |
1105 double newDuration = double(p.getDuration()) * ratio; | |
1106 | |
1107 Event newPoint = p | |
1108 .withFrame(lrint(newFrame)) | |
1109 .withDuration(lrint(newDuration)); | |
1110 command->remove(p); | |
1111 command->add(newPoint); | |
1112 } | |
1113 | |
1114 finish(command); | |
1115 } | |
1116 | |
1117 void | |
1118 NoteLayer::deleteSelection(Selection s) | |
1119 { | |
1152 if (!m_model) return; | 1120 if (!m_model) return; |
1153 | 1121 |
1154 NoteModel::EditCommand *command = | 1122 ChangeEventsCommand *command = |
1155 new NoteModel::EditCommand(m_model, tr("Resize Selection")); | 1123 new ChangeEventsCommand(m_model, tr("Delete Selected Points")); |
1156 | 1124 |
1157 NoteModel::PointList points = | 1125 EventVector points = |
1158 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | 1126 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
1159 | 1127 |
1160 double ratio = | 1128 for (Event p: points) { |
1161 double(newSize.getEndFrame() - newSize.getStartFrame()) / | 1129 command->remove(p); |
1162 double(s.getEndFrame() - s.getStartFrame()); | |
1163 | |
1164 for (NoteModel::PointList::iterator i = points.begin(); | |
1165 i != points.end(); ++i) { | |
1166 | |
1167 if (s.contains(i->frame)) { | |
1168 | |
1169 double targetStart = double(i->frame); | |
1170 targetStart = double(newSize.getStartFrame()) + | |
1171 targetStart - double(s.getStartFrame()) * ratio; | |
1172 | |
1173 double targetEnd = double(i->frame + i->duration); | |
1174 targetEnd = double(newSize.getStartFrame()) + | |
1175 targetEnd - double(s.getStartFrame()) * ratio; | |
1176 | |
1177 NoteModel::Point newPoint(*i); | |
1178 newPoint.frame = lrint(targetStart); | |
1179 newPoint.duration = lrint(targetEnd - targetStart); | |
1180 command->deletePoint(*i); | |
1181 command->addPoint(newPoint); | |
1182 } | |
1183 } | |
1184 | |
1185 finish(command); | |
1186 } | |
1187 | |
1188 void | |
1189 NoteLayer::deleteSelection(Selection s) | |
1190 { | |
1191 if (!m_model) return; | |
1192 | |
1193 NoteModel::EditCommand *command = | |
1194 new NoteModel::EditCommand(m_model, tr("Delete Selected Points")); | |
1195 | |
1196 NoteModel::PointList points = | |
1197 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
1198 | |
1199 for (NoteModel::PointList::iterator i = points.begin(); | |
1200 i != points.end(); ++i) { | |
1201 | |
1202 if (s.contains(i->frame)) { | |
1203 command->deletePoint(*i); | |
1204 } | |
1205 } | 1130 } |
1206 | 1131 |
1207 finish(command); | 1132 finish(command); |
1208 } | 1133 } |
1209 | 1134 |
1210 void | 1135 void |
1211 NoteLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) | 1136 NoteLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) |
1212 { | 1137 { |
1213 if (!m_model) return; | 1138 if (!m_model) return; |
1214 | 1139 |
1215 NoteModel::PointList points = | 1140 EventVector points = |
1216 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | 1141 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
1217 | 1142 |
1218 for (NoteModel::PointList::iterator i = points.begin(); | 1143 for (Event p: points) { |
1219 i != points.end(); ++i) { | 1144 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); |
1220 if (s.contains(i->frame)) { | |
1221 Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label); | |
1222 point.setReferenceFrame(alignToReference(v, i->frame)); | |
1223 to.addPoint(point); | |
1224 } | |
1225 } | 1145 } |
1226 } | 1146 } |
1227 | 1147 |
1228 bool | 1148 bool |
1229 NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) | 1149 NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, |
1150 sv_frame_t /* frameOffset */, bool /* interactive */) | |
1230 { | 1151 { |
1231 if (!m_model) return false; | 1152 if (!m_model) return false; |
1232 | 1153 |
1233 const Clipboard::PointList &points = from.getPoints(); | 1154 const EventVector &points = from.getPoints(); |
1234 | 1155 |
1235 bool realign = false; | 1156 bool realign = false; |
1236 | 1157 |
1237 if (clipboardHasDifferentAlignment(v, from)) { | 1158 if (clipboardHasDifferentAlignment(v, from)) { |
1238 | 1159 |
1249 if (button == QMessageBox::Yes) { | 1170 if (button == QMessageBox::Yes) { |
1250 realign = true; | 1171 realign = true; |
1251 } | 1172 } |
1252 } | 1173 } |
1253 | 1174 |
1254 NoteModel::EditCommand *command = | 1175 ChangeEventsCommand *command = |
1255 new NoteModel::EditCommand(m_model, tr("Paste")); | 1176 new ChangeEventsCommand(m_model, tr("Paste")); |
1256 | 1177 |
1257 for (Clipboard::PointList::const_iterator i = points.begin(); | 1178 for (EventVector::const_iterator i = points.begin(); |
1258 i != points.end(); ++i) { | 1179 i != points.end(); ++i) { |
1259 | 1180 |
1260 if (!i->haveFrame()) continue; | |
1261 sv_frame_t frame = 0; | 1181 sv_frame_t frame = 0; |
1262 | 1182 |
1263 if (!realign) { | 1183 if (!realign) { |
1264 | 1184 |
1265 frame = i->getFrame(); | 1185 frame = i->getFrame(); |
1266 | 1186 |
1267 } else { | 1187 } else { |
1268 | 1188 |
1269 if (i->haveReferenceFrame()) { | 1189 if (i->hasReferenceFrame()) { |
1270 frame = i->getReferenceFrame(); | 1190 frame = i->getReferenceFrame(); |
1271 frame = alignFromReference(v, frame); | 1191 frame = alignFromReference(v, frame); |
1272 } else { | 1192 } else { |
1273 frame = i->getFrame(); | 1193 frame = i->getFrame(); |
1274 } | 1194 } |
1275 } | 1195 } |
1276 | 1196 |
1277 NoteModel::Point newPoint(frame); | 1197 Event p = *i; |
1278 | 1198 Event newPoint = p; |
1279 if (i->haveLabel()) newPoint.label = i->getLabel(); | 1199 if (!p.hasValue()) { |
1280 if (i->haveValue()) newPoint.value = i->getValue(); | 1200 newPoint = newPoint.withValue((m_model->getValueMinimum() + |
1281 else newPoint.value = (m_model->getValueMinimum() + | 1201 m_model->getValueMaximum()) / 2); |
1282 m_model->getValueMaximum()) / 2; | 1202 } |
1283 if (i->haveLevel()) newPoint.level = i->getLevel(); | 1203 if (!p.hasDuration()) { |
1284 if (i->haveDuration()) newPoint.duration = i->getDuration(); | |
1285 else { | |
1286 sv_frame_t nextFrame = frame; | 1204 sv_frame_t nextFrame = frame; |
1287 Clipboard::PointList::const_iterator j = i; | 1205 EventVector::const_iterator j = i; |
1288 for (; j != points.end(); ++j) { | 1206 for (; j != points.end(); ++j) { |
1289 if (!j->haveFrame()) continue; | |
1290 if (j != i) break; | 1207 if (j != i) break; |
1291 } | 1208 } |
1292 if (j != points.end()) { | 1209 if (j != points.end()) { |
1293 nextFrame = j->getFrame(); | 1210 nextFrame = j->getFrame(); |
1294 } | 1211 } |
1295 if (nextFrame == frame) { | 1212 if (nextFrame == frame) { |
1296 newPoint.duration = m_model->getResolution(); | 1213 newPoint = newPoint.withDuration(m_model->getResolution()); |
1297 } else { | 1214 } else { |
1298 newPoint.duration = nextFrame - frame; | 1215 newPoint = newPoint.withDuration(nextFrame - frame); |
1299 } | 1216 } |
1300 } | 1217 } |
1301 | 1218 |
1302 command->addPoint(newPoint); | 1219 command->add(newPoint); |
1303 } | 1220 } |
1304 | 1221 |
1305 finish(command); | 1222 finish(command); |
1306 return true; | 1223 return true; |
1307 } | 1224 } |
1308 | 1225 |
1309 void | 1226 void |
1310 NoteLayer::addNoteOn(sv_frame_t frame, int pitch, int velocity) | 1227 NoteLayer::addNoteOn(sv_frame_t frame, int pitch, int velocity) |
1311 { | 1228 { |
1312 m_pendingNoteOns.insert(Note(frame, float(pitch), 0, float(velocity) / 127.f, "")); | 1229 m_pendingNoteOns.insert(Event(frame, float(pitch), 0, |
1230 float(velocity) / 127.f, QString())); | |
1313 } | 1231 } |
1314 | 1232 |
1315 void | 1233 void |
1316 NoteLayer::addNoteOff(sv_frame_t frame, int pitch) | 1234 NoteLayer::addNoteOff(sv_frame_t frame, int pitch) |
1317 { | 1235 { |
1318 for (NoteSet::iterator i = m_pendingNoteOns.begin(); | 1236 for (NoteSet::iterator i = m_pendingNoteOns.begin(); |
1319 i != m_pendingNoteOns.end(); ++i) { | 1237 i != m_pendingNoteOns.end(); ++i) { |
1320 if (lrintf((*i).value) == pitch) { | 1238 |
1321 Note note(*i); | 1239 Event p = *i; |
1240 | |
1241 if (lrintf(p.getValue()) == pitch) { | |
1322 m_pendingNoteOns.erase(i); | 1242 m_pendingNoteOns.erase(i); |
1323 note.duration = frame - note.frame; | 1243 Event note = p.withDuration(frame - p.getFrame()); |
1324 if (m_model) { | 1244 if (m_model) { |
1325 NoteModel::AddPointCommand *c = new NoteModel::AddPointCommand | 1245 ChangeEventsCommand *c = new ChangeEventsCommand |
1326 (m_model, note, tr("Record Note")); | 1246 (m_model, tr("Record Note")); |
1247 c->add(note); | |
1327 // execute and bundle: | 1248 // execute and bundle: |
1328 CommandHistory::getInstance()->addCommand(c, true, true); | 1249 CommandHistory::getInstance()->addCommand(c, true, true); |
1329 } | 1250 } |
1330 break; | 1251 break; |
1331 } | 1252 } |