2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sigc++/bind.h>
30 #include "pbd/failed_constructor.h"
31 #include "pbd/stl_delete.h"
32 #include "pbd/xml++.h"
33 #include "pbd/stacktrace.h"
35 #include "ardour/playlist.h"
36 #include "ardour/session.h"
37 #include "ardour/region.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/playlist_factory.h"
40 #include "ardour/transient_detector.h"
45 using namespace ARDOUR;
48 struct ShowMeTheList {
49 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
53 boost::shared_ptr<Playlist> playlist;
57 struct RegionSortByLayer {
58 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
59 return a->layer() < b->layer();
63 struct RegionSortByLayerWithPending {
64 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
66 double p = a->layer ();
67 if (a->pending_explicit_relayer()) {
71 double q = b->layer ();
72 if (b->pending_explicit_relayer()) {
80 struct RegionSortByPosition {
81 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
82 return a->position() < b->position();
86 struct RegionSortByLastLayerOp {
87 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
88 return a->last_layer_op() < b->last_layer_op();
93 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
94 : SessionObject(sess, nom)
98 first_set_state = false;
103 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
104 : SessionObject(sess, "unnamed playlist")
107 const XMLProperty* prop = node.property("type");
108 assert(!prop || DataType(prop->value()) == _type);
111 _name = "unnamed"; /* reset by set_state */
113 /* set state called by derived class */
116 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
117 : SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
122 other->copy_regions (tmp);
126 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
127 add_region_internal( (*x), (*x)->position());
132 _splicing = other->_splicing;
133 _nudging = other->_nudging;
134 _edit_mode = other->_edit_mode;
137 first_set_state = false;
139 in_partition = false;
141 _read_data_count = 0;
142 _frozen = other->_frozen;
144 layer_op_counter = other->layer_op_counter;
145 freeze_length = other->freeze_length;
148 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
149 : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
151 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
153 nframes_t end = start + cnt - 1;
159 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
161 boost::shared_ptr<Region> region;
162 boost::shared_ptr<Region> new_region;
163 nframes_t offset = 0;
164 nframes_t position = 0;
171 overlap = region->coverage (start, end);
177 case OverlapInternal:
178 offset = start - region->position();
185 position = region->position() - start;
186 len = end - region->position();
190 offset = start - region->position();
192 len = region->length() - offset;
195 case OverlapExternal:
197 position = region->position() - start;
198 len = region->length();
202 _session.region_name (new_name, region->name(), false);
204 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
206 add_region_internal (new_region, position);
210 first_set_state = false;
212 /* this constructor does NOT notify others (session) */
219 InUse (true); /* EMIT SIGNAL */
230 InUse (false); /* EMIT SIGNAL */
235 Playlist::copy_regions (RegionList& newlist) const
237 RegionLock rlock (const_cast<Playlist *> (this));
239 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
240 newlist.push_back (RegionFactory::RegionFactory::create (*i));
245 Playlist::init (bool hide)
247 g_atomic_int_set (&block_notifications, 0);
248 g_atomic_int_set (&ignore_state_changes, 0);
249 pending_modified = false;
250 pending_length = false;
251 first_set_state = true;
258 _edit_mode = Config->get_edit_mode();
260 in_partition = false;
262 _read_data_count = 0;
264 layer_op_counter = 0;
266 _explicit_relayering = false;
268 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
271 Playlist::~Playlist ()
274 RegionLock rl (this);
276 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
277 (*i)->set_playlist (boost::shared_ptr<Playlist>());
281 /* GoingAway must be emitted by derived classes */
285 Playlist::set_name (const string& str)
287 /* in a typical situation, a playlist is being used
288 by one diskstream and also is referenced by the
289 Session. if there are more references than that,
290 then don't change the name.
296 return SessionObject::set_name(str);
300 /***********************************************************************
301 CHANGE NOTIFICATION HANDLING
303 Notifications must be delayed till the region_lock is released. This
304 is necessary because handlers for the signals may need to acquire
305 the lock (e.g. to read from the playlist).
306 ***********************************************************************/
311 delay_notifications ();
312 g_atomic_int_inc (&ignore_state_changes);
318 g_atomic_int_dec_and_test (&ignore_state_changes);
319 release_notifications ();
324 Playlist::delay_notifications ()
326 g_atomic_int_inc (&block_notifications);
327 freeze_length = _get_maximum_extent();
331 Playlist::release_notifications ()
333 if (g_atomic_int_dec_and_test (&block_notifications)) {
334 flush_notifications ();
339 Playlist::notify_modified ()
341 if (holding_state ()) {
342 pending_modified = true;
344 pending_modified = false;
345 Modified(); /* EMIT SIGNAL */
350 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
352 if (holding_state ()) {
353 pending_removes.insert (r);
354 pending_modified = true;
355 pending_length = true;
357 /* this might not be true, but we have to act
358 as though it could be.
360 pending_length = false;
361 LengthChanged (); /* EMIT SIGNAL */
362 pending_modified = false;
363 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
364 Modified (); /* EMIT SIGNAL */
369 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
371 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
373 if (holding_state ()) {
375 pending_range_moves.push_back (move);
379 list< Evoral::RangeMove<nframes_t> > m;
387 Playlist::notify_region_added (boost::shared_ptr<Region> r)
389 /* the length change might not be true, but we have to act
390 as though it could be.
393 if (holding_state()) {
394 pending_adds.insert (r);
395 pending_modified = true;
396 pending_length = true;
398 pending_length = false;
399 LengthChanged (); /* EMIT SIGNAL */
400 pending_modified = false;
401 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
402 Modified (); /* EMIT SIGNAL */
407 Playlist::notify_length_changed ()
409 if (holding_state ()) {
410 pending_length = true;
412 pending_length = false;
413 LengthChanged(); /* EMIT SIGNAL */
414 pending_modified = false;
415 Modified (); /* EMIT SIGNAL */
420 Playlist::flush_notifications ()
422 set<boost::shared_ptr<Region> > dependent_checks_needed;
423 set<boost::shared_ptr<Region> >::iterator s;
432 /* we have no idea what order the regions ended up in pending
433 bounds (it could be based on selection order, for example).
434 so, to preserve layering in the "most recently moved is higher"
435 model, sort them by existing layer, then timestamp them.
438 // RegionSortByLayer cmp;
439 // pending_bounds.sort (cmp);
441 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
442 if (_session.config.get_layer_model() == MoveAddHigher) {
443 timestamp_layer_op (*r);
446 pending_length = true;
447 dependent_checks_needed.insert (*r);
452 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
453 remove_dependents (*s);
454 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
458 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
459 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
460 dependent_checks_needed.insert (*s);
464 if ((freeze_length != _get_maximum_extent()) || pending_length) {
466 LengthChanged(); /* EMIT SIGNAL */
470 if (n || pending_modified) {
474 pending_modified = false;
475 Modified (); /* EMIT SIGNAL */
478 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
479 check_dependents (*s, false);
482 if (!pending_range_moves.empty ()) {
483 RangesMoved (pending_range_moves);
486 pending_adds.clear ();
487 pending_removes.clear ();
488 pending_bounds.clear ();
489 pending_range_moves.clear ();
494 /*************************************************************
496 *************************************************************/
499 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
501 RegionLock rlock (this);
502 times = fabs (times);
504 int itimes = (int) floor (times);
506 nframes_t pos = position;
508 if(times == 1 && auto_partition){
509 partition(pos, (nframes_t) (pos + region->length()), true);
513 add_region_internal (region, pos);
514 pos += region->length();
519 /* note that itimes can be zero if we being asked to just
520 insert a single fraction of the region.
523 for (int i = 0; i < itimes; ++i) {
524 boost::shared_ptr<Region> copy = RegionFactory::create (region);
525 add_region_internal (copy, pos);
526 pos += region->length();
529 nframes_t length = 0;
531 if (floor (times) != times) {
532 length = (nframes_t) floor (region->length() * (times - floor (times)));
534 _session.region_name (name, region->name(), false);
535 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
536 add_region_internal (sub, pos);
539 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
543 Playlist::set_region_ownership ()
545 RegionLock rl (this);
546 RegionList::iterator i;
547 boost::weak_ptr<Playlist> pl (shared_from_this());
549 for (i = regions.begin(); i != regions.end(); ++i) {
550 (*i)->set_playlist (pl);
555 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
557 if (region->data_type() != _type){
561 RegionSortByPosition cmp;
563 nframes_t old_length = 0;
565 if (!holding_state()) {
566 old_length = _get_maximum_extent();
569 if (!first_set_state) {
570 boost::shared_ptr<Playlist> foo (shared_from_this());
571 region->set_playlist (boost::weak_ptr<Playlist>(foo));
574 region->set_position (position, this);
576 timestamp_layer_op (region);
578 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
579 all_regions.insert (region);
581 possibly_splice_unlocked (position, region->length(), region);
583 if (!holding_state () && !in_set_state) {
584 /* layers get assigned from XML state */
588 /* we need to notify the existence of new region before checking dependents. Ick. */
590 notify_region_added (region);
592 if (!holding_state ()) {
594 check_dependents (region, false);
596 if (old_length != _get_maximum_extent()) {
597 notify_length_changed ();
601 region_state_changed_connections.push_back (
602 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
603 boost::weak_ptr<Region> (region)))
610 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
612 RegionLock rlock (this);
614 bool old_sp = _splicing;
617 remove_region_internal (old);
618 add_region_internal (newr, pos);
622 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
626 Playlist::remove_region (boost::shared_ptr<Region> region)
628 RegionLock rlock (this);
629 remove_region_internal (region);
633 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
635 RegionList::iterator i;
636 nframes_t old_length = 0;
638 if (!holding_state()) {
639 old_length = _get_maximum_extent();
644 region->set_playlist (boost::weak_ptr<Playlist>());
647 for (i = regions.begin(); i != regions.end(); ++i) {
650 nframes_t pos = (*i)->position();
651 nframes64_t distance = (*i)->length();
655 possibly_splice_unlocked (pos, -distance);
657 if (!holding_state ()) {
659 remove_dependents (region);
661 if (old_length != _get_maximum_extent()) {
662 notify_length_changed ();
666 notify_region_removed (region);
677 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
679 if (Config->get_use_overlap_equivalency()) {
680 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
681 if ((*i)->overlap_equivalent (other)) {
682 results.push_back ((*i));
686 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
687 if ((*i)->equivalent (other)) {
688 results.push_back ((*i));
695 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
697 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
699 if ((*i) && (*i)->region_list_equivalent (other)) {
700 results.push_back (*i);
706 Playlist::partition (nframes_t start, nframes_t end, bool cut)
710 partition_internal (start, end, cut, thawlist);
712 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
713 (*i)->thaw ("separation");
718 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
720 RegionList new_regions;
723 RegionLock rlock (this);
725 boost::shared_ptr<Region> region;
726 boost::shared_ptr<Region> current;
728 RegionList::iterator tmp;
730 nframes_t pos1, pos2, pos3, pos4;
734 /* need to work from a copy, because otherwise the regions we add during the process
735 get operated on as well.
738 RegionList copy = regions;
740 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
747 if (current->first_frame() >= start && current->last_frame() < end) {
750 remove_region_internal (current);
756 /* coverage will return OverlapStart if the start coincides
757 with the end point. we do not partition such a region,
758 so catch this special case.
761 if (current->first_frame() >= end) {
765 if ((overlap = current->coverage (start, end)) == OverlapNone) {
769 pos1 = current->position();
772 pos4 = current->last_frame();
774 if (overlap == OverlapInternal) {
775 /* split: we need 3 new regions, the front, middle and end.
776 cut: we need 2 regions, the front and end.
781 ---------------*************************------------
784 ---------------*****++++++++++++++++====------------
786 ---------------*****----------------====------------
791 /* "middle" ++++++ */
793 _session.region_name (new_name, current->name(), false);
794 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
795 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
796 add_region_internal (region, start);
797 new_regions.push_back (region);
802 _session.region_name (new_name, current->name(), false);
803 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
804 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
806 add_region_internal (region, end);
807 new_regions.push_back (region);
812 thawlist.push_back (current);
813 current->trim_end (pos2, this);
815 } else if (overlap == OverlapEnd) {
819 ---------------*************************------------
822 ---------------**************+++++++++++------------
824 ---------------**************-----------------------
831 _session.region_name (new_name, current->name(), false);
832 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
833 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
835 add_region_internal (region, start);
836 new_regions.push_back (region);
842 thawlist.push_back (current);
843 current->trim_end (pos2, this);
845 } else if (overlap == OverlapStart) {
847 /* split: we need 2 regions: the front and the end.
848 cut: just trim current to skip the cut area
853 ---------------*************************------------
857 ---------------****+++++++++++++++++++++------------
859 -------------------*********************------------
865 _session.region_name (new_name, current->name(), false);
866 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
867 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
869 add_region_internal (region, pos1);
870 new_regions.push_back (region);
876 thawlist.push_back (current);
877 current->trim_front (pos3, this);
878 } else if (overlap == OverlapExternal) {
880 /* split: no split required.
881 cut: remove the region.
886 ---------------*************************------------
890 ---------------*************************------------
892 ----------------------------------------------------
897 remove_region_internal (current);
900 new_regions.push_back (current);
904 in_partition = false;
907 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
908 check_dependents (*i, false);
912 boost::shared_ptr<Playlist>
913 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
915 boost::shared_ptr<Playlist> ret;
916 boost::shared_ptr<Playlist> pl;
919 if (ranges.empty()) {
920 return boost::shared_ptr<Playlist>();
923 start = ranges.front().start;
925 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
927 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
929 if (i == ranges.begin()) {
933 /* paste the next section into the nascent playlist,
934 offset to reflect the start of the first range we
938 ret->paste (pl, (*i).start - start, 1.0f);
945 boost::shared_ptr<Playlist>
946 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
948 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
949 return cut_copy (pmf, ranges, result_is_hidden);
952 boost::shared_ptr<Playlist>
953 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
955 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
956 return cut_copy (pmf, ranges, result_is_hidden);
959 boost::shared_ptr<Playlist>
960 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
962 boost::shared_ptr<Playlist> the_copy;
966 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
967 string new_name = _name;
971 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
972 return boost::shared_ptr<Playlist>();
975 partition_internal (start, start+cnt-1, true, thawlist);
977 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
978 (*i)->thaw ("playlist cut");
984 boost::shared_ptr<Playlist>
985 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
989 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
990 string new_name = _name;
994 cnt = min (_get_maximum_extent() - start, cnt);
995 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
999 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
1001 times = fabs (times);
1002 nframes_t old_length;
1005 RegionLock rl1 (this);
1006 RegionLock rl2 (other.get());
1008 old_length = _get_maximum_extent();
1010 int itimes = (int) floor (times);
1011 nframes_t pos = position;
1012 nframes_t shift = other->_get_maximum_extent();
1013 layer_t top_layer = regions.size();
1016 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1017 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1019 /* put these new regions on top of all existing ones, but preserve
1020 the ordering they had in the original playlist.
1023 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1024 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1030 /* XXX shall we handle fractional cases at some point? */
1032 if (old_length != _get_maximum_extent()) {
1033 notify_length_changed ();
1044 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1046 times = fabs (times);
1048 RegionLock rl (this);
1049 int itimes = (int) floor (times);
1050 nframes_t pos = position;
1053 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1054 add_region_internal (copy, pos);
1055 pos += region->length();
1058 if (floor (times) != times) {
1059 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1061 _session.region_name (name, region->name(), false);
1062 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1063 add_region_internal (sub, pos);
1068 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1070 RegionLock rlock (this);
1071 RegionList copy (regions);
1074 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1076 if ((*r)->last_frame() < at) {
1081 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1082 /* intersected region */
1083 if (!move_intersected) {
1088 /* do not move regions glued to music time - that
1089 has to be done separately.
1092 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1093 fixup.push_back (*r);
1097 (*r)->set_position ((*r)->position() + distance, this);
1100 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1101 (*r)->recompute_position_from_lock_style ();
1106 Playlist::split (nframes64_t at)
1108 RegionLock rlock (this);
1109 RegionList copy (regions);
1111 /* use a copy since this operation can modify the region list
1114 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1115 _split_region (*r, at);
1120 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1122 RegionLock rl (this);
1123 _split_region (region, playlist_position);
1127 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1129 if (!region->covers (playlist_position)) {
1133 if (region->position() == playlist_position ||
1134 region->last_frame() == playlist_position) {
1138 boost::shared_ptr<Region> left;
1139 boost::shared_ptr<Region> right;
1145 /* split doesn't change anything about length, so don't try to splice */
1147 bool old_sp = _splicing;
1150 before = playlist_position - region->position();
1151 after = region->length() - before;
1153 _session.region_name (before_name, region->name(), false);
1154 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1156 _session.region_name (after_name, region->name(), false);
1157 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1159 add_region_internal (left, region->position());
1160 add_region_internal (right, region->position() + before);
1162 uint64_t orig_layer_op = region->last_layer_op();
1163 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1164 if ((*i)->last_layer_op() > orig_layer_op) {
1165 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1169 left->set_last_layer_op ( orig_layer_op );
1170 right->set_last_layer_op ( orig_layer_op + 1);
1174 finalize_split_region (region, left, right);
1176 remove_region_internal (region);
1182 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1184 if (_splicing || in_set_state) {
1185 /* don't respond to splicing moves or state setting */
1189 if (_edit_mode == Splice) {
1190 splice_locked (at, distance, exclude);
1195 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1197 if (_splicing || in_set_state) {
1198 /* don't respond to splicing moves or state setting */
1202 if (_edit_mode == Splice) {
1203 splice_unlocked (at, distance, exclude);
1208 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1211 RegionLock rl (this);
1212 core_splice (at, distance, exclude);
1217 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1219 core_splice (at, distance, exclude);
1223 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1227 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1229 if (exclude && (*i) == exclude) {
1233 if ((*i)->position() >= at) {
1234 nframes64_t new_pos = (*i)->position() + distance;
1237 } else if (new_pos >= max_frames - (*i)->length()) {
1238 new_pos = max_frames - (*i)->length();
1241 (*i)->set_position (new_pos, this);
1247 notify_length_changed ();
1251 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1253 if (in_set_state || _splicing || _nudging || _shuffling) {
1257 if (what_changed & ARDOUR::PositionChanged) {
1259 /* remove it from the list then add it back in
1260 the right place again.
1263 RegionSortByPosition cmp;
1265 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1267 if (i == regions.end()) {
1268 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1269 _name, region->name())
1275 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1278 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1280 nframes64_t delta = 0;
1282 if (what_changed & ARDOUR::PositionChanged) {
1283 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1286 if (what_changed & ARDOUR::LengthChanged) {
1287 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1291 possibly_splice (region->last_position() + region->last_length(), delta, region);
1294 if (holding_state ()) {
1295 pending_bounds.push_back (region);
1297 if (_session.config.get_layer_model() == MoveAddHigher) {
1298 /* it moved or changed length, so change the timestamp */
1299 timestamp_layer_op (region);
1302 notify_length_changed ();
1304 check_dependents (region, false);
1310 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1312 boost::shared_ptr<Region> region (weak_region.lock());
1319 /* this makes a virtual call to the right kind of playlist ... */
1321 region_changed (what_changed, region);
1325 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1327 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1330 if (in_set_state || in_flush) {
1334 if (what_changed & BoundsChanged) {
1335 region_bounds_changed (what_changed, region);
1336 save = !(_splicing || _nudging);
1339 if ((what_changed & our_interests) &&
1340 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1341 check_dependents (region, false);
1344 if (what_changed & Change (ARDOUR::PositionChanged)) {
1345 notify_region_moved (region);
1348 if (what_changed & our_interests) {
1356 Playlist::drop_regions ()
1358 RegionLock rl (this);
1360 all_regions.clear ();
1364 Playlist::clear (bool with_signals)
1367 RegionLock rl (this);
1370 std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
1371 i != region_state_changed_connections.end ();
1377 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1378 pending_removes.insert (*i);
1385 pending_length = false;
1387 pending_modified = false;
1393 /***********************************************************************
1395 **********************************************************************/
1397 Playlist::RegionList *
1398 Playlist::regions_at (nframes_t frame)
1401 RegionLock rlock (this);
1402 return find_regions_at (frame);
1405 boost::shared_ptr<Region>
1406 Playlist::top_region_at (nframes_t frame)
1409 RegionLock rlock (this);
1410 RegionList *rlist = find_regions_at (frame);
1411 boost::shared_ptr<Region> region;
1413 if (rlist->size()) {
1414 RegionSortByLayer cmp;
1416 region = rlist->back();
1423 boost::shared_ptr<Region>
1424 Playlist::top_unmuted_region_at (nframes_t frame)
1427 RegionLock rlock (this);
1428 RegionList *rlist = find_regions_at (frame);
1430 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1432 RegionList::iterator tmp = i;
1435 if ((*i)->muted()) {
1442 boost::shared_ptr<Region> region;
1444 if (rlist->size()) {
1445 RegionSortByLayer cmp;
1447 region = rlist->back();
1454 Playlist::RegionList*
1455 Playlist::regions_to_read (nframes_t start, nframes_t end)
1457 /* Caller must hold lock */
1459 RegionList covering;
1460 set<nframes_t> to_check;
1461 set<boost::shared_ptr<Region> > unique;
1464 to_check.insert (start);
1465 to_check.insert (end);
1467 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1469 /* find all/any regions that span start+end */
1471 switch ((*i)->coverage (start, end)) {
1475 case OverlapInternal:
1476 covering.push_back (*i);
1480 to_check.insert ((*i)->position());
1481 covering.push_back (*i);
1485 to_check.insert ((*i)->last_frame());
1486 covering.push_back (*i);
1489 case OverlapExternal:
1490 covering.push_back (*i);
1491 to_check.insert ((*i)->position());
1492 to_check.insert ((*i)->last_frame());
1496 /* don't go too far */
1498 if ((*i)->position() > end) {
1503 RegionList* rlist = new RegionList;
1505 /* find all the regions that cover each position .... */
1507 if (covering.size() == 1) {
1509 rlist->push_back (covering.front());
1513 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1517 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1519 if ((*x)->covers (*t)) {
1520 here.push_back (*x);
1524 RegionSortByLayer cmp;
1527 /* ... and get the top/transparent regions at "here" */
1529 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1533 if ((*c)->opaque()) {
1535 /* the other regions at this position are hidden by this one */
1542 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1543 rlist->push_back (*s);
1546 if (rlist->size() > 1) {
1547 /* now sort by time order */
1549 RegionSortByPosition cmp;
1557 Playlist::RegionList *
1558 Playlist::find_regions_at (nframes_t frame)
1560 /* Caller must hold lock */
1562 RegionList *rlist = new RegionList;
1564 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1565 if ((*i)->covers (frame)) {
1566 rlist->push_back (*i);
1573 Playlist::RegionList *
1574 Playlist::regions_touched (nframes_t start, nframes_t end)
1576 RegionLock rlock (this);
1577 RegionList *rlist = new RegionList;
1579 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1580 if ((*i)->coverage (start, end) != OverlapNone) {
1581 rlist->push_back (*i);
1589 Playlist::find_next_transient (nframes64_t from, int dir)
1591 RegionLock rlock (this);
1592 AnalysisFeatureList points;
1593 AnalysisFeatureList these_points;
1595 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1597 if ((*i)->last_frame() < from) {
1601 if ((*i)->first_frame() > from) {
1606 (*i)->get_transients (these_points);
1608 /* add first frame, just, err, because */
1610 these_points.push_back ((*i)->first_frame());
1612 points.insert (points.end(), these_points.begin(), these_points.end());
1613 these_points.clear ();
1616 if (points.empty()) {
1620 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1621 bool reached = false;
1624 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1629 if (reached && (*x) > from) {
1634 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1639 if (reached && (*x) < from) {
1648 boost::shared_ptr<Region>
1649 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1651 RegionLock rlock (this);
1652 boost::shared_ptr<Region> ret;
1653 nframes_t closest = max_frames;
1655 bool end_iter = false;
1657 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1662 boost::shared_ptr<Region> r = (*i);
1667 pos = r->first_frame ();
1670 pos = r->last_frame ();
1673 pos = r->sync_position ();
1674 // r->adjust_to_sync (r->first_frame());
1679 case 1: /* forwards */
1682 if ((distance = pos - frame) < closest) {
1691 default: /* backwards */
1694 if ((distance = frame - pos) < closest) {
1711 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1713 RegionLock rlock (this);
1715 nframes64_t closest = max_frames;
1716 nframes64_t ret = -1;
1720 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1722 boost::shared_ptr<Region> r = (*i);
1723 nframes64_t distance;
1725 if (r->first_frame() > frame) {
1727 distance = r->first_frame() - frame;
1729 if (distance < closest) {
1730 ret = r->first_frame();
1735 if (r->last_frame () > frame) {
1737 distance = r->last_frame () - frame;
1739 if (distance < closest) {
1740 ret = r->last_frame ();
1748 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1750 boost::shared_ptr<Region> r = (*i);
1751 nframes64_t distance;
1753 if (r->last_frame() < frame) {
1755 distance = frame - r->last_frame();
1757 if (distance < closest) {
1758 ret = r->last_frame();
1763 if (r->first_frame() < frame) {
1765 distance = frame - r->first_frame();
1767 if (distance < closest) {
1768 ret = r->first_frame();
1778 /***********************************************************************/
1784 Playlist::mark_session_dirty ()
1786 if (!in_set_state && !holding_state ()) {
1787 _session.set_dirty();
1792 Playlist::set_state (const XMLNode& node)
1796 XMLNodeConstIterator niter;
1797 XMLPropertyList plist;
1798 XMLPropertyConstIterator piter;
1800 boost::shared_ptr<Region> region;
1805 if (node.name() != "Playlist") {
1812 plist = node.properties();
1814 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1818 if (prop->name() == X_("name")) {
1819 _name = prop->value();
1820 } else if (prop->name() == X_("orig_diskstream_id")) {
1821 _orig_diskstream_id = prop->value ();
1822 } else if (prop->name() == X_("frozen")) {
1823 _frozen = (prop->value() == X_("yes"));
1829 nlist = node.children();
1831 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1835 if (child->name() == "Region") {
1837 if ((prop = child->property ("id")) == 0) {
1838 error << _("region state node has no ID, ignored") << endmsg;
1842 ID id = prop->value ();
1844 if ((region = region_by_id (id))) {
1846 Change what_changed = Change (0);
1848 if (region->set_live_state (*child, what_changed, true)) {
1849 error << _("Playlist: cannot reset region state from XML") << endmsg;
1853 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1854 error << _("Playlist: cannot create region from XML") << endmsg;
1858 add_region (region, region->position(), 1.0);
1860 // So that layer_op ordering doesn't get screwed up
1861 region->set_last_layer_op( region->layer());
1870 /* update dependents, which was not done during add_region_internal
1871 due to in_set_state being true
1874 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1875 check_dependents (*r, false);
1879 first_set_state = false;
1884 Playlist::get_state()
1886 return state (true);
1890 Playlist::get_template()
1892 return state (false);
1895 /** @param full_state true to include regions in the returned state, otherwise false.
1898 Playlist::state (bool full_state)
1900 XMLNode *node = new XMLNode (X_("Playlist"));
1903 node->add_property (X_("name"), _name);
1904 node->add_property (X_("type"), _type.to_string());
1906 _orig_diskstream_id.print (buf, sizeof (buf));
1907 node->add_property (X_("orig_diskstream_id"), buf);
1908 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1911 RegionLock rlock (this, false);
1912 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1913 node->add_child_nocopy ((*i)->get_state());
1918 node->add_child_copy (*_extra_xml);
1925 Playlist::empty() const
1927 RegionLock rlock (const_cast<Playlist *>(this), false);
1928 return regions.empty();
1932 Playlist::n_regions() const
1934 RegionLock rlock (const_cast<Playlist *>(this), false);
1935 return regions.size();
1939 Playlist::get_maximum_extent () const
1941 RegionLock rlock (const_cast<Playlist *>(this), false);
1942 return _get_maximum_extent ();
1946 Playlist::_get_maximum_extent () const
1948 RegionList::const_iterator i;
1949 nframes_t max_extent = 0;
1952 for (i = regions.begin(); i != regions.end(); ++i) {
1953 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1962 Playlist::bump_name (string name, Session &session)
1964 string newname = name;
1967 newname = bump_name_once (newname);
1968 } while (session.playlist_by_name (newname)!=NULL);
1975 Playlist::top_layer() const
1977 RegionLock rlock (const_cast<Playlist *> (this));
1980 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1981 top = max (top, (*i)->layer());
1987 Playlist::set_edit_mode (EditMode mode)
1992 /********************
1994 ********************/
1997 Playlist::relayer ()
1999 /* don't send multiple Modified notifications
2000 when multiple regions are relayered.
2005 /* Build up a new list of regions on each layer, stored in a set of lists
2006 each of which represent some period of time on some layer. The idea
2007 is to avoid having to search the entire region list to establish whether
2008 each region overlaps another */
2010 /* how many pieces to divide this playlist's time up into */
2011 int const divisions = 512;
2013 /* find the start and end positions of the regions on this playlist */
2014 nframes_t start = UINT_MAX;
2016 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2017 start = min (start, (*i)->position());
2018 end = max (end, (*i)->position() + (*i)->length());
2021 /* hence the size of each time division */
2022 double const division_size = (end - start) / divisions;
2024 vector<vector<RegionList> > layers;
2025 layers.push_back (vector<RegionList> (divisions));
2027 /* we want to go through regions from desired lowest to desired highest layer,
2028 which depends on the layer model
2031 RegionList copy = regions;
2033 /* sort according to the model and the layering mode that we're in */
2035 if (_explicit_relayering) {
2037 copy.sort (RegionSortByLayerWithPending ());
2039 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2041 copy.sort (RegionSortByLastLayerOp ());
2045 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2047 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2048 (*i)->set_pending_explicit_relayer (false);
2050 /* find the time divisions that this region covers */
2051 int const start_division = floor ( ((*i)->position() - start) / division_size);
2052 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2053 if (end_division == divisions) {
2057 /* find the lowest layer that this region can go on */
2058 size_t j = layers.size();
2060 /* try layer j - 1; it can go on if it overlaps no other region
2061 that is already on that layer
2064 bool overlap = false;
2065 for (int k = start_division; k <= end_division; ++k) {
2066 RegionList::iterator l = layers[j-1][k].begin ();
2067 while (l != layers[j-1][k].end()) {
2068 if ((*l)->overlap_equivalent (*i)) {
2081 /* overlap, so we must use layer j */
2088 if (j == layers.size()) {
2089 /* we need a new layer for this region */
2090 layers.push_back (vector<RegionList> (divisions));
2093 /* put a reference to this region in each of the divisions that it exists in */
2094 for (int k = start_division; k <= end_division; ++k) {
2095 layers[j][k].push_back (*i);
2098 (*i)->set_layer (j);
2101 /* sending Modified means that various kinds of layering
2102 models operate correctly at the GUI
2103 level. slightly inefficient, but only slightly.
2105 We force a Modified signal here in case no layers actually
2114 /* XXX these layer functions are all deprecated */
2117 Playlist::raise_region (boost::shared_ptr<Region> region)
2119 uint32_t rsz = regions.size();
2120 layer_t target = region->layer() + 1U;
2122 if (target >= rsz) {
2123 /* its already at the effective top */
2127 move_region_to_layer (target, region, 1);
2131 Playlist::lower_region (boost::shared_ptr<Region> region)
2133 if (region->layer() == 0) {
2134 /* its already at the bottom */
2138 layer_t target = region->layer() - 1U;
2140 move_region_to_layer (target, region, -1);
2144 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2146 /* does nothing useful if layering mode is later=higher */
2147 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2148 (_session.config.get_layer_model() == AddHigher)) {
2149 timestamp_layer_op (region);
2155 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2157 /* does nothing useful if layering mode is later=higher */
2158 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2159 (_session.config.get_layer_model() == AddHigher)) {
2160 region->set_last_layer_op (0);
2166 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2168 RegionList::iterator i;
2169 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2170 list<LayerInfo> layerinfo;
2174 RegionLock rlock (const_cast<Playlist *> (this));
2176 for (i = regions.begin(); i != regions.end(); ++i) {
2184 /* region is moving up, move all regions on intermediate layers
2188 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2189 dest = (*i)->layer() - 1;
2196 /* region is moving down, move all regions on intermediate layers
2200 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2201 dest = (*i)->layer() + 1;
2211 newpair.second = dest;
2213 layerinfo.push_back (newpair);
2217 /* now reset the layers without holding the region lock */
2219 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2220 x->first->set_layer (x->second);
2223 region->set_layer (target_layer);
2226 /* now check all dependents */
2228 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2229 check_dependents (x->first, false);
2232 check_dependents (region, false);
2239 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2241 RegionList::iterator i;
2248 RegionLock rlock (const_cast<Playlist *> (this));
2250 for (i = regions.begin(); i != regions.end(); ++i) {
2252 if ((*i)->position() >= start) {
2256 if ((*i)->last_frame() > max_frames - distance) {
2257 new_pos = max_frames - (*i)->length();
2259 new_pos = (*i)->position() + distance;
2264 if ((*i)->position() > distance) {
2265 new_pos = (*i)->position() - distance;
2271 (*i)->set_position (new_pos, this);
2279 notify_length_changed ();
2284 boost::shared_ptr<Region>
2285 Playlist::find_region (const ID& id) const
2287 RegionLock rlock (const_cast<Playlist*> (this));
2289 /* searches all regions currently in use by the playlist */
2291 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2292 if ((*i)->id() == id) {
2297 return boost::shared_ptr<Region> ();
2300 boost::shared_ptr<Region>
2301 Playlist::region_by_id (ID id)
2303 /* searches all regions ever added to this playlist */
2305 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2306 if ((*i)->id() == id) {
2310 return boost::shared_ptr<Region> ();
2314 Playlist::dump () const
2316 boost::shared_ptr<Region> r;
2318 cerr << "Playlist \"" << _name << "\" " << endl
2319 << regions.size() << " regions "
2322 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2324 cerr << " " << r->name() << " ["
2325 << r->start() << "+" << r->length()
2335 Playlist::set_frozen (bool yn)
2341 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2343 // struct timeval tv;
2344 // gettimeofday (&tv, 0);
2345 region->set_last_layer_op (++layer_op_counter);
2350 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2355 if (region->locked()) {
2362 RegionLock rlock (const_cast<Playlist*> (this));
2367 RegionList::iterator next;
2369 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2370 if ((*i) == region) {
2374 if (next != regions.end()) {
2376 if ((*next)->locked()) {
2380 if ((*next)->position() != region->last_frame() + 1) {
2381 /* they didn't used to touch, so after shuffle,
2382 just have them swap positions.
2384 new_pos = (*next)->position();
2386 /* they used to touch, so after shuffle,
2387 make sure they still do. put the earlier
2388 region where the later one will end after
2391 new_pos = region->position() + (*next)->length();
2394 (*next)->set_position (region->position(), this);
2395 region->set_position (new_pos, this);
2397 /* avoid a full sort */
2399 regions.erase (i); // removes the region from the list */
2401 regions.insert (next, region); // adds it back after next
2410 RegionList::iterator prev = regions.end();
2412 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2413 if ((*i) == region) {
2415 if (prev != regions.end()) {
2417 if ((*prev)->locked()) {
2421 if (region->position() != (*prev)->last_frame() + 1) {
2422 /* they didn't used to touch, so after shuffle,
2423 just have them swap positions.
2425 new_pos = region->position();
2427 /* they used to touch, so after shuffle,
2428 make sure they still do. put the earlier
2429 one where the later one will end after
2431 new_pos = (*prev)->position() + region->length();
2434 region->set_position ((*prev)->position(), this);
2435 (*prev)->set_position (new_pos, this);
2437 /* avoid a full sort */
2439 regions.erase (i); // remove region
2440 regions.insert (prev, region); // insert region before prev
2456 check_dependents (region, false);
2464 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2466 RegionLock rlock (const_cast<Playlist*> (this));
2468 if (regions.size() > 1) {
2476 Playlist::update_after_tempo_map_change ()
2478 RegionLock rlock (const_cast<Playlist*> (this));
2479 RegionList copy (regions);
2483 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2484 (*i)->update_position_after_tempo_map_change ();
2491 Playlist::foreach_region (sigc::slot<void, boost::shared_ptr<Region> > s)
2493 RegionLock rl (this, false);
2494 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2500 Playlist::set_explicit_relayering (bool e)
2502 if (e == false && _explicit_relayering == true) {
2504 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2505 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2506 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2507 at this point would keep regions on the same layers.
2509 From then on in, it's just you and your towel.
2512 RegionLock rl (this);
2513 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2514 (*i)->set_last_layer_op ((*i)->layer ());
2518 _explicit_relayering = e;