diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h index e308cae6b5..101d4f2450 100644 --- a/libs/ardour/ardour/location.h +++ b/libs/ardour/ardour/location.h @@ -258,6 +258,8 @@ public: bool clear_cue_markers (samplepos_t start, samplepos_t end); + void cut_copy_section (timepos_t const& start, timepos_t const& end, timepos_t const& to, bool const copy); + void ripple (timepos_t const & at, timecnt_t const & distance, bool include_locked, bool notify); XMLNode& get_state () const; diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc index fb03d48247..27d7810347 100644 --- a/libs/ardour/location.cc +++ b/libs/ardour/location.cc @@ -1680,6 +1680,87 @@ Locations::ripple (timepos_t const & at, timecnt_t const & distance, bool includ } } +void +Locations::cut_copy_section (timepos_t const& start, timepos_t const& end, timepos_t const& to, bool const copy) +{ + LocationList ll; + + { + Glib::Threads::RWLock::WriterLock lm (_lock); + ll = locations; + } + + for (auto const& i : ll) { + if (i->is_session_range () || i->is_auto_punch () || i->is_auto_loop ()) { + continue; + } + if (i->locked ()) { + continue; + } + + if (!i->is_mark ()) { + if (i->start () >= start && i->end () <= end) { + /* range is inside the selction, process it */ + } else if (i->start () < start && i->end () < start) { + /* range is entirely outside the selection, possible ripple it */ + } else if (i->start () >= end && i->end () >= end) { + /* range is entirely outside the selection, possible ripple it */ + } else { + // TODO - How do we handle ranges that intersect start/end ? + continue; + } + } + + if (!copy) { + timecnt_t distance = timecnt_t (i->start ().time_domain ()); + + if (i->start () < start) { + /* Not affected, unless paste-point `to` is earlier, + * in which case we need to make space there + */ + if (i->start () >= to) { + distance = start.distance(end); + } + } + else if (i->start () >= end) { + /* data before this mark is "cut", so move it towards 0, unless + * the whole cut/paste operation is earlier, in which case this mark + * is not affected. + */ + if (i->start () <= to + start.distance(end)) { + distance = end.distance(start); + } + } + else { + /* process cut/paste */ + distance = start.distance (to); + } + + + if (i->is_mark ()) { + i->set_start (i->start () + distance); + continue; + } + + /* process range-end, by default use same distance as i->start + * to retain the range length, but additionally consider the following. + */ + timecnt_t dist_end = distance; + if (i->end () >= end) { + if (i->end () > to + start.distance(end)) { + /* paste inside range, extend range: keep range end */ + dist_end = timecnt_t (i->end ().time_domain ()); + } + } + + i->set (i->start () + distance, i->end () + dist_end); + + } else { + // TODO Copy/Paste: add new markers, disambiugate names + } + } +} + bool Locations::clear_cue_markers (samplepos_t start, samplepos_t end) { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index d9d13a76a6..e4b57d0597 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -7206,7 +7206,6 @@ Session::cut_copy_section (timepos_t const& start, timepos_t const& end, timepos pl->clear_owned_changes (); std::shared_ptr p = copy ? pl->copy (ltr) : pl->cut (ltr); - // TODO copy interpolated MIDI events if (!copy) { pl->ripple (start, end.distance(start), NULL); } @@ -7230,11 +7229,19 @@ Session::cut_copy_section (timepos_t const& start, timepos_t const& end, timepos Config->set_automation_follows_regions (automation_follows); } + /* automation */ for (auto& r : *(routes.reader())) { r->cut_copy_section (start, end, to, copy); } - // TODO: update ranges and Tempo-Map + { + XMLNode &before = _locations->get_state(); + _locations->cut_copy_section (start, end, to, copy); + XMLNode &after = _locations->get_state(); + add_command (new MementoCommand (*_locations, &before, &after)); + } + + // TODO: update Tempo-Map if (!abort_empty_reversible_command ()) { commit_reversible_command ();