+ 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_pulse = _session.tempo_map().exact_qn_at_frame (position, sub_num) / 4.0;
+ const double pulse_delta = pos_pulse - pulse();
+
+ /* 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) {
+ /* sets _beat to new position.*/
+ set_position_internal (position, true, sub_num);
+ what_changed.add (Properties::position);
+
+ const double new_start_pulse = (_start_beats.val().to_double() / 4.0) + pulse_delta;
+ const framepos_t new_start = _position - _session.tempo_map().frame_at_pulse (pulse() - new_start_pulse);
+
+ if (!verify_start_and_length (new_start, length)) {
+ return;
+ }
+
+ _start_beats = Evoral::Beats (new_start_pulse * 4.0);
+ what_changed.add (Properties::start_beats);
+
+ set_start_internal (new_start, sub_num);
+ what_changed.add (Properties::start);
+ }
+
+ if (_length != length) {
+
+ if (!verify_start_and_length (_start, length)) {
+ return;
+ }
+
+ 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);
+ }