+ framepos_t new_start;
+
+ if (locked()) {
+ return;
+ }
+
+ PropertyChange what_changed;
+
+ /* beat has been set exactly by set_position_internal, but the source starts on a frame.
+ working in beats seems the correct thing to do, but reports of a missing first note
+ on playback suggest otherwise. for now, we work in exact beats.
+ */
+ const double pos_beat = _session.tempo_map().exact_beat_at_frame (position, sub_num);
+ const double beat_delta = pos_beat - beat();
+
+ /* Set position before length, otherwise for MIDI regions this bad thing happens:
+ * 1. we call set_length_internal; length in beats is computed using the region's current
+ * (soon-to-be old) position
+ * 2. we call set_position_internal; position is set and length in frames re-computed using
+ * length in beats from (1) but at the new position, which is wrong if the region
+ * straddles a tempo/meter change.
+ */
+
+ if (_position != position) {
+ set_position_internal (position, true, sub_num);
+ what_changed.add (Properties::position);
+ }
+
+ const double new_start_beat = _start_beats.val().to_double() + beat_delta;
+ new_start = _position - _session.tempo_map().frame_at_beat (beat() - new_start_beat);
+
+ if (!verify_start_and_length (new_start, length)) {
+ return;
+ }
+
+ if (_start != new_start) {
+ _start_beats = Evoral::Beats (new_start_beat);
+ what_changed.add (Properties::start_beats);
+
+ set_start_internal (new_start, sub_num);
+ what_changed.add (Properties::start);
+ }
+
+ if (_length != length) {
+ set_length_internal (length, sub_num);
+ what_changed.add (Properties::length);
+ what_changed.add (Properties::length_beats);
+ }
+
+ set_whole_file (false);
+
+ PropertyChange start_and_length;
+
+ start_and_length.add (Properties::start);
+ start_and_length.add (Properties::length);
+
+ if (what_changed.contains (start_and_length)) {
+ first_edit ();
+ }
+
+ if (!what_changed.empty()) {
+ send_change (what_changed);
+ }