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 }