+ if (locked()) {
+ return;
+ }
+
+ PropertyChange what_changed;
+
+
+ /* 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 samples 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) {
+
+ const double pos_qn = _session.tempo_map().exact_qn_at_sample (position, sub_num);
+ const double old_pos_qn = quarter_note();
+
+ /* sets _pulse to new position.*/
+ set_position_internal (position, true, sub_num);
+ what_changed.add (Properties::position);
+
+ double new_start_qn = start_beats() + (pos_qn - old_pos_qn);
+ samplepos_t new_start = _session.tempo_map().samples_between_quarter_notes (pos_qn - new_start_qn, pos_qn);
+
+ if (!verify_start_and_length (new_start, length)) {
+ return;
+ }
+
+ _start_beats = new_start_qn;
+ 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);
+ }