diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 698352e9a8..fe20b33b12 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -586,6 +586,7 @@ public: bool should_ripple () const; void do_ripple (boost::shared_ptr, samplepos_t, samplecnt_t, ARDOUR::RegionList* exclude, bool add_to_command); void do_ripple (boost::shared_ptr, samplepos_t, samplecnt_t, boost::shared_ptr exclude, bool add_to_command); + void ripple_marks (boost::shared_ptr target_playlist, samplepos_t at, samplecnt_t distance); void add_region_marker (); void clear_region_markers (); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 4e8aa11b69..9bcdc9d2c5 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -1839,9 +1839,7 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const changed_t /* Ripple marks & ranges if appropriate */ if (Config->get_edit_mode() == RippleAll) { - XMLNode& before (_editor->session()->locations()->get_state()); - _editor->session()->locations()->ripple (extent_min, extent_max - extent_min, false, true); - _editor->session()->add_command (new MementoCommand (*_editor->session()->locations(), &before, &_editor->session()->locations()->get_state())); + _editor->ripple_marks (_primary->region()->playlist(), extent_min, extent_max - extent_min); } /* If we've created new regions either by copying or moving @@ -2089,14 +2087,6 @@ RegionMoveDrag::finished_no_copy ( _editor->selection->set (new_views); } - /* Ripple marks & ranges if appropriate */ - - if (Config->get_edit_mode() == RippleAll) { - XMLNode& before (_editor->session()->locations()->get_state()); - _editor->session()->locations()->ripple (extent_min, -drag_delta, false, true); - _editor->session()->add_command (new MementoCommand (*_editor->session()->locations(), &before, &_editor->session()->locations()->get_state())); - } - _editor->commit_reversible_command (); /* We have futzed with the layering of canvas items on our streamviews. diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index a2d1e7d9fe..f22cbf0ce4 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -9272,10 +9272,39 @@ Editor::do_ripple (boost::shared_ptr target_playlist, samplepos_t at, /* Ripple marks & ranges if appropriate */ - if (Config->get_edit_mode() == RippleAll) { - XMLNode& before (_session->locations()->get_state()); - /* do not move locked markers, do notify */ - _session->locations()->ripple (at, distance, false, true); - _session->add_command (new MementoCommand (*_session->locations(), &before, &_session->locations()->get_state())); + if (Config->get_edit_mode() != RippleAll) { + cerr << "out here\n"; + return; } + + ripple_marks (target_playlist, at, distance); +} + +void +Editor::ripple_marks (boost::shared_ptr target_playlist, samplepos_t at, samplecnt_t distance) +{ + /* in the target playlist, find the region before the target + * (implicitly given by @param at. Allow all markers that occur between + * the end of the region and @param at to move too. This is + * desired/expected by many (most?) ripple-edit using folk. + */ + + boost::shared_ptr rl = target_playlist->region_list(); + samplepos_t last_region_end_before_at = 0; + + for (RegionList::const_iterator r = rl->begin(); r != rl->end(); ++r) { + samplepos_t region_end = (*r)->position() + (*r)->length(); + if (region_end > last_region_end_before_at && region_end < at) { + last_region_end_before_at = region_end; + } + } + + if (last_region_end_before_at < at) { + at = last_region_end_before_at + 1; + } + + XMLNode& before (_session->locations()->get_state()); + /* do not move locked markers, do notify */ + _session->locations()->ripple (at, distance, false, true); + _session->add_command (new MementoCommand (*_session->locations(), &before, &_session->locations()->get_state())); } diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc index 3d47d37344..3f4040c23f 100644 --- a/libs/ardour/location.cc +++ b/libs/ardour/location.cc @@ -1616,47 +1616,50 @@ Locations::range_starts_at(samplepos_t pos, samplecnt_t slop, bool incl) const void Locations::ripple (samplepos_t at, samplecnt_t distance, bool include_locked, bool notify) { + LocationList copy; + { Glib::Threads::RWLock::WriterLock lm (_lock); + copy = locations; + } - for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) { + for (LocationList::iterator i = copy.begin(); i != copy.end(); ++i) { - /* keep session range markers covering entire region if - a ripple "extends" the session. - */ - if (distance > 0 && (*i)->is_session_range()) { + /* keep session range markers covering entire region if + a ripple "extends" the session. + */ + if (distance > 0 && (*i)->is_session_range()) { - /* Don't move start unless it occurs after the ripple point. - */ - if ((*i)->start() >= at) { - (*i)->set ((*i)->start() + distance, (*i)->end() + distance); - } else { - (*i)->set_end ((*i)->end() + distance); - } + /* Don't move start unless it occurs after the ripple point. + */ + if ((*i)->start() >= at) { + (*i)->set ((*i)->start() + distance, (*i)->end() + distance); + } else { + (*i)->set_end ((*i)->end() + distance); + } + continue; + } + + bool locked = (*i)->locked(); + + if (locked) { + if (!include_locked) { continue; } + } else { + (*i)->unlock (); + } - bool locked = (*i)->locked(); + if ((*i)->start() >= at) { + (*i)->set_start ((*i)->start() + distance); - if (locked) { - if (!include_locked) { - continue; - } - } else { - (*i)->unlock (); + if (!(*i)->is_mark()) { + (*i)->set_end ((*i)->end() + distance); } + } - if ((*i)->start() >= at) { - (*i)->set_start ((*i)->start() + distance); - - if (!(*i)->is_mark()) { - (*i)->set_end ((*i)->end() + distance); - } - } - - if (locked) { - (*i)->lock(); - } + if (locked) { + (*i)->lock(); } }