+/** Move automation around according to a list of region movements.
+ * @param return true if anything was changed, otherwise false (ie nothing needed changing)
+ */
+bool
+ControlList::move_ranges (const list< RangeMove<double> >& movements)
+{
+ typedef list< RangeMove<double> > RangeMoveList;
+
+ {
+ Glib::Mutex::Lock lm (_lock);
+
+ /* a copy of the events list before we started moving stuff around */
+ EventList old_events = _events;
+
+ /* clear the source and destination ranges in the new list */
+ bool things_erased = false;
+ for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
+
+ if (erase_range_internal (i->from, i->from + i->length, _events)) {
+ things_erased = true;
+ }
+
+ if (erase_range_internal (i->to, i->to + i->length, _events)) {
+ things_erased = true;
+ }
+ }
+
+ /* if nothing was erased, there is nothing to do */
+ if (!things_erased) {
+ return false;
+ }
+
+ /* copy the events into the new list */
+ for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
+ iterator j = old_events.begin ();
+ const double limit = i->from + i->length;
+ const double dx = i->to - i->from;
+ while (j != old_events.end () && (*j)->when <= limit) {
+ if ((*j)->when >= i->from) {
+ ControlEvent* ev = new ControlEvent (**j);
+ ev->when += dx;
+ _events.push_back (ev);
+ }
+ ++j;
+ }
+ }
+
+ if (!_frozen) {
+ _events.sort (event_time_less_than);
+ } else {
+ _sort_pending = true;
+ }
+
+ mark_dirty ();
+ }
+
+ maybe_signal_changed ();
+ return true;
+}
+
+void
+ControlList::set_interpolation (InterpolationStyle s)
+{
+ if (_interpolation == s) {
+ return;
+ }
+
+ _interpolation = s;
+ InterpolationChanged (s); /* EMIT SIGNAL */
+}
+
+void
+ControlList::set_thinning_factor (double v)
+{
+ _thinning_factor = v;
+}
+