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.
29 #include "pbd/failed_constructor.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/xml++.h"
32 #include "pbd/stacktrace.h"
34 #include "ardour/debug.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"
41 #include "ardour/session_playlists.h"
46 using namespace ARDOUR;
49 struct ShowMeTheList {
50 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
52 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
54 boost::shared_ptr<Playlist> playlist;
58 struct RegionSortByLayer {
59 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
60 return a->layer() < b->layer();
64 struct RegionSortByLayerWithPending {
65 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
67 double p = a->layer ();
68 if (a->pending_explicit_relayer()) {
72 double q = b->layer ();
73 if (b->pending_explicit_relayer()) {
81 struct RegionSortByPosition {
82 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
83 return a->position() < b->position();
87 struct RegionSortByLastLayerOp {
88 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
89 return a->last_layer_op() < b->last_layer_op();
94 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
95 : SessionObject(sess, nom)
99 first_set_state = false;
104 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
105 : SessionObject(sess, "unnamed playlist")
108 const XMLProperty* prop = node.property("type");
109 assert(!prop || DataType(prop->value()) == _type);
112 _name = "unnamed"; /* reset by set_state */
114 /* set state called by derived class */
117 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
118 : SessionObject(other->_session, namestr)
119 , _type(other->_type)
120 , _orig_diskstream_id(other->_orig_diskstream_id)
125 other->copy_regions (tmp);
129 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
130 add_region_internal( (*x), (*x)->position());
135 _splicing = other->_splicing;
136 _nudging = other->_nudging;
137 _edit_mode = other->_edit_mode;
140 first_set_state = false;
142 in_partition = false;
144 _read_data_count = 0;
145 _frozen = other->_frozen;
147 layer_op_counter = other->layer_op_counter;
148 freeze_length = other->freeze_length;
151 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
152 : SessionObject(other->_session, str)
153 , _type(other->_type)
154 , _orig_diskstream_id(other->_orig_diskstream_id)
156 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
158 nframes_t end = start + cnt - 1;
164 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
166 boost::shared_ptr<Region> region;
167 boost::shared_ptr<Region> new_region;
168 nframes_t offset = 0;
169 nframes_t position = 0;
176 overlap = region->coverage (start, end);
182 case OverlapInternal:
183 offset = start - region->position();
190 position = region->position() - start;
191 len = end - region->position();
195 offset = start - region->position();
197 len = region->length() - offset;
200 case OverlapExternal:
202 position = region->position() - start;
203 len = region->length();
207 _session.region_name (new_name, region->name(), false);
209 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
211 add_region_internal (new_region, position);
215 first_set_state = false;
217 /* this constructor does NOT notify others (session) */
224 InUse (true); /* EMIT SIGNAL */
235 InUse (false); /* EMIT SIGNAL */
240 Playlist::copy_regions (RegionList& newlist) const
242 RegionLock rlock (const_cast<Playlist *> (this));
244 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
245 newlist.push_back (RegionFactory::RegionFactory::create (*i));
250 Playlist::init (bool hide)
252 g_atomic_int_set (&block_notifications, 0);
253 g_atomic_int_set (&ignore_state_changes, 0);
254 pending_modified = false;
255 pending_length = false;
256 first_set_state = true;
263 _edit_mode = Config->get_edit_mode();
265 in_partition = false;
267 _read_data_count = 0;
269 layer_op_counter = 0;
271 _explicit_relayering = false;
273 Modified.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
276 Playlist::~Playlist ()
278 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
281 RegionLock rl (this);
283 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
284 (*i)->set_playlist (boost::shared_ptr<Playlist>());
288 /* GoingAway must be emitted by derived classes */
292 Playlist::set_name (const string& str)
294 /* in a typical situation, a playlist is being used
295 by one diskstream and also is referenced by the
296 Session. if there are more references than that,
297 then don't change the name.
303 return SessionObject::set_name(str);
307 /***********************************************************************
308 CHANGE NOTIFICATION HANDLING
310 Notifications must be delayed till the region_lock is released. This
311 is necessary because handlers for the signals may need to acquire
312 the lock (e.g. to read from the playlist).
313 ***********************************************************************/
318 delay_notifications ();
319 g_atomic_int_inc (&ignore_state_changes);
325 g_atomic_int_dec_and_test (&ignore_state_changes);
326 release_notifications ();
331 Playlist::delay_notifications ()
333 g_atomic_int_inc (&block_notifications);
334 freeze_length = _get_maximum_extent();
338 Playlist::release_notifications ()
340 if (g_atomic_int_dec_and_test (&block_notifications)) {
341 flush_notifications ();
346 Playlist::notify_modified ()
348 if (holding_state ()) {
349 pending_modified = true;
351 pending_modified = false;
352 Modified(); /* EMIT SIGNAL */
357 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
359 if (holding_state ()) {
360 pending_removes.insert (r);
361 pending_modified = true;
362 pending_length = true;
364 /* this might not be true, but we have to act
365 as though it could be.
367 pending_length = false;
368 LengthChanged (); /* EMIT SIGNAL */
369 pending_modified = false;
370 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
371 Modified (); /* EMIT SIGNAL */
376 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
378 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
380 if (holding_state ()) {
382 pending_range_moves.push_back (move);
386 list< Evoral::RangeMove<nframes_t> > m;
394 Playlist::notify_region_added (boost::shared_ptr<Region> r)
396 /* the length change might not be true, but we have to act
397 as though it could be.
400 if (holding_state()) {
401 pending_adds.insert (r);
402 pending_modified = true;
403 pending_length = true;
405 pending_length = false;
406 LengthChanged (); /* EMIT SIGNAL */
407 pending_modified = false;
408 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
409 Modified (); /* EMIT SIGNAL */
414 Playlist::notify_length_changed ()
416 if (holding_state ()) {
417 pending_length = true;
419 pending_length = false;
420 LengthChanged(); /* EMIT SIGNAL */
421 pending_modified = false;
422 Modified (); /* EMIT SIGNAL */
427 Playlist::flush_notifications ()
429 set<boost::shared_ptr<Region> > dependent_checks_needed;
430 set<boost::shared_ptr<Region> >::iterator s;
439 /* we have no idea what order the regions ended up in pending
440 bounds (it could be based on selection order, for example).
441 so, to preserve layering in the "most recently moved is higher"
442 model, sort them by existing layer, then timestamp them.
445 // RegionSortByLayer cmp;
446 // pending_bounds.sort (cmp);
448 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
449 if (_session.config.get_layer_model() == MoveAddHigher) {
450 timestamp_layer_op (*r);
453 pending_length = true;
454 dependent_checks_needed.insert (*r);
459 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
460 remove_dependents (*s);
461 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
465 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
466 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
467 dependent_checks_needed.insert (*s);
471 if ((freeze_length != _get_maximum_extent()) || pending_length) {
473 LengthChanged(); /* EMIT SIGNAL */
477 if (n || pending_modified) {
481 pending_modified = false;
482 Modified (); /* EMIT SIGNAL */
485 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
486 check_dependents (*s, false);
489 if (!pending_range_moves.empty ()) {
490 RangesMoved (pending_range_moves);
493 pending_adds.clear ();
494 pending_removes.clear ();
495 pending_bounds.clear ();
496 pending_range_moves.clear ();
501 /*************************************************************
503 *************************************************************/
506 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
508 RegionLock rlock (this);
509 times = fabs (times);
511 int itimes = (int) floor (times);
513 nframes_t pos = position;
515 if (times == 1 && auto_partition){
516 partition(pos, (nframes_t) (pos + region->length()), true);
520 add_region_internal (region, pos);
521 pos += region->length();
526 /* note that itimes can be zero if we being asked to just
527 insert a single fraction of the region.
530 for (int i = 0; i < itimes; ++i) {
531 boost::shared_ptr<Region> copy = RegionFactory::create (region);
532 add_region_internal (copy, pos);
533 pos += region->length();
536 nframes_t length = 0;
538 if (floor (times) != times) {
539 length = (nframes_t) floor (region->length() * (times - floor (times)));
541 _session.region_name (name, region->name(), false);
542 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
543 add_region_internal (sub, pos);
546 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
550 Playlist::set_region_ownership ()
552 RegionLock rl (this);
553 RegionList::iterator i;
554 boost::weak_ptr<Playlist> pl (shared_from_this());
556 for (i = regions.begin(); i != regions.end(); ++i) {
557 (*i)->set_playlist (pl);
562 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
564 if (region->data_type() != _type){
568 RegionSortByPosition cmp;
570 nframes_t old_length = 0;
572 if (!holding_state()) {
573 old_length = _get_maximum_extent();
576 if (!first_set_state) {
577 boost::shared_ptr<Playlist> foo (shared_from_this());
578 region->set_playlist (boost::weak_ptr<Playlist>(foo));
581 region->set_position (position, this);
583 timestamp_layer_op (region);
585 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
586 all_regions.insert (region);
588 possibly_splice_unlocked (position, region->length(), region);
590 if (!holding_state () && !in_set_state) {
591 /* layers get assigned from XML state */
595 /* we need to notify the existence of new region before checking dependents. Ick. */
597 notify_region_added (region);
599 if (!holding_state ()) {
601 check_dependents (region, false);
603 if (old_length != _get_maximum_extent()) {
604 notify_length_changed ();
608 region->StateChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
614 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
616 RegionLock rlock (this);
618 bool old_sp = _splicing;
621 remove_region_internal (old);
622 add_region_internal (newr, pos);
626 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
630 Playlist::remove_region (boost::shared_ptr<Region> region)
632 RegionLock rlock (this);
633 remove_region_internal (region);
637 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
639 RegionList::iterator i;
640 nframes_t old_length = 0;
642 if (!holding_state()) {
643 old_length = _get_maximum_extent();
648 region->set_playlist (boost::weak_ptr<Playlist>());
651 for (i = regions.begin(); i != regions.end(); ++i) {
654 nframes_t pos = (*i)->position();
655 nframes64_t distance = (*i)->length();
659 possibly_splice_unlocked (pos, -distance);
661 if (!holding_state ()) {
663 remove_dependents (region);
665 if (old_length != _get_maximum_extent()) {
666 notify_length_changed ();
670 notify_region_removed (region);
681 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
683 if (Config->get_use_overlap_equivalency()) {
684 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
685 if ((*i)->overlap_equivalent (other)) {
686 results.push_back ((*i));
690 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
691 if ((*i)->equivalent (other)) {
692 results.push_back ((*i));
699 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
701 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
703 if ((*i) && (*i)->region_list_equivalent (other)) {
704 results.push_back (*i);
710 Playlist::partition (nframes_t start, nframes_t end, bool cut)
714 partition_internal (start, end, cut, thawlist);
716 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
717 (*i)->thaw ("separation");
722 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
724 RegionList new_regions;
727 RegionLock rlock (this);
729 boost::shared_ptr<Region> region;
730 boost::shared_ptr<Region> current;
732 RegionList::iterator tmp;
734 nframes_t pos1, pos2, pos3, pos4;
738 /* need to work from a copy, because otherwise the regions we add during the process
739 get operated on as well.
742 RegionList copy = regions;
744 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
751 if (current->first_frame() >= start && current->last_frame() < end) {
754 remove_region_internal (current);
760 /* coverage will return OverlapStart if the start coincides
761 with the end point. we do not partition such a region,
762 so catch this special case.
765 if (current->first_frame() >= end) {
769 if ((overlap = current->coverage (start, end)) == OverlapNone) {
773 pos1 = current->position();
776 pos4 = current->last_frame();
778 if (overlap == OverlapInternal) {
779 /* split: we need 3 new regions, the front, middle and end.
780 cut: we need 2 regions, the front and end.
785 ---------------*************************------------
788 ---------------*****++++++++++++++++====------------
790 ---------------*****----------------====------------
795 /* "middle" ++++++ */
797 _session.region_name (new_name, current->name(), false);
798 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
799 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
800 add_region_internal (region, start);
801 new_regions.push_back (region);
806 _session.region_name (new_name, current->name(), false);
807 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
808 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
810 add_region_internal (region, end);
811 new_regions.push_back (region);
816 thawlist.push_back (current);
817 current->trim_end (pos2, this);
819 } else if (overlap == OverlapEnd) {
823 ---------------*************************------------
826 ---------------**************+++++++++++------------
828 ---------------**************-----------------------
835 _session.region_name (new_name, current->name(), false);
836 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
837 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
839 add_region_internal (region, start);
840 new_regions.push_back (region);
846 thawlist.push_back (current);
847 current->trim_end (pos2, this);
849 } else if (overlap == OverlapStart) {
851 /* split: we need 2 regions: the front and the end.
852 cut: just trim current to skip the cut area
857 ---------------*************************------------
861 ---------------****+++++++++++++++++++++------------
863 -------------------*********************------------
869 _session.region_name (new_name, current->name(), false);
870 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
871 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
873 add_region_internal (region, pos1);
874 new_regions.push_back (region);
880 thawlist.push_back (current);
881 current->trim_front (pos3, this);
882 } else if (overlap == OverlapExternal) {
884 /* split: no split required.
885 cut: remove the region.
890 ---------------*************************------------
894 ---------------*************************------------
896 ----------------------------------------------------
901 remove_region_internal (current);
904 new_regions.push_back (current);
908 in_partition = false;
911 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
912 check_dependents (*i, false);
916 boost::shared_ptr<Playlist>
917 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
919 boost::shared_ptr<Playlist> ret;
920 boost::shared_ptr<Playlist> pl;
923 if (ranges.empty()) {
924 return boost::shared_ptr<Playlist>();
927 start = ranges.front().start;
929 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
931 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
933 if (i == ranges.begin()) {
937 /* paste the next section into the nascent playlist,
938 offset to reflect the start of the first range we
942 ret->paste (pl, (*i).start - start, 1.0f);
949 boost::shared_ptr<Playlist>
950 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
952 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
953 return cut_copy (pmf, ranges, result_is_hidden);
956 boost::shared_ptr<Playlist>
957 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
959 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
960 return cut_copy (pmf, ranges, result_is_hidden);
963 boost::shared_ptr<Playlist>
964 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
966 boost::shared_ptr<Playlist> the_copy;
970 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
971 string new_name = _name;
975 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
976 return boost::shared_ptr<Playlist>();
979 partition_internal (start, start+cnt-1, true, thawlist);
981 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
982 (*i)->thaw ("playlist cut");
988 boost::shared_ptr<Playlist>
989 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
993 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
994 string new_name = _name;
998 cnt = min (_get_maximum_extent() - start, cnt);
999 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1003 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
1005 times = fabs (times);
1006 nframes_t old_length;
1009 RegionLock rl1 (this);
1010 RegionLock rl2 (other.get());
1012 old_length = _get_maximum_extent();
1014 int itimes = (int) floor (times);
1015 nframes_t pos = position;
1016 nframes_t shift = other->_get_maximum_extent();
1017 layer_t top_layer = regions.size();
1020 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1021 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1023 /* put these new regions on top of all existing ones, but preserve
1024 the ordering they had in the original playlist.
1027 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1028 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1034 /* XXX shall we handle fractional cases at some point? */
1036 if (old_length != _get_maximum_extent()) {
1037 notify_length_changed ();
1048 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1050 times = fabs (times);
1052 RegionLock rl (this);
1053 int itimes = (int) floor (times);
1054 nframes_t pos = position;
1057 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1058 add_region_internal (copy, pos);
1059 pos += region->length();
1062 if (floor (times) != times) {
1063 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1065 _session.region_name (name, region->name(), false);
1066 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1067 add_region_internal (sub, pos);
1072 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1074 RegionLock rlock (this);
1075 RegionList copy (regions);
1078 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1080 if ((*r)->last_frame() < at) {
1085 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1086 /* intersected region */
1087 if (!move_intersected) {
1092 /* do not move regions glued to music time - that
1093 has to be done separately.
1096 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1097 fixup.push_back (*r);
1101 (*r)->set_position ((*r)->position() + distance, this);
1104 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1105 (*r)->recompute_position_from_lock_style ();
1110 Playlist::split (nframes64_t at)
1112 RegionLock rlock (this);
1113 RegionList copy (regions);
1115 /* use a copy since this operation can modify the region list
1118 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1119 _split_region (*r, at);
1124 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1126 RegionLock rl (this);
1127 _split_region (region, playlist_position);
1131 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1133 if (!region->covers (playlist_position)) {
1137 if (region->position() == playlist_position ||
1138 region->last_frame() == playlist_position) {
1142 boost::shared_ptr<Region> left;
1143 boost::shared_ptr<Region> right;
1149 /* split doesn't change anything about length, so don't try to splice */
1151 bool old_sp = _splicing;
1154 before = playlist_position - region->position();
1155 after = region->length() - before;
1157 _session.region_name (before_name, region->name(), false);
1158 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1160 _session.region_name (after_name, region->name(), false);
1161 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1163 add_region_internal (left, region->position());
1164 add_region_internal (right, region->position() + before);
1166 uint64_t orig_layer_op = region->last_layer_op();
1167 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1168 if ((*i)->last_layer_op() > orig_layer_op) {
1169 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1173 left->set_last_layer_op ( orig_layer_op );
1174 right->set_last_layer_op ( orig_layer_op + 1);
1178 finalize_split_region (region, left, right);
1180 remove_region_internal (region);
1186 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1188 if (_splicing || in_set_state) {
1189 /* don't respond to splicing moves or state setting */
1193 if (_edit_mode == Splice) {
1194 splice_locked (at, distance, exclude);
1199 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1201 if (_splicing || in_set_state) {
1202 /* don't respond to splicing moves or state setting */
1206 if (_edit_mode == Splice) {
1207 splice_unlocked (at, distance, exclude);
1212 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1215 RegionLock rl (this);
1216 core_splice (at, distance, exclude);
1221 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1223 core_splice (at, distance, exclude);
1227 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1231 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1233 if (exclude && (*i) == exclude) {
1237 if ((*i)->position() >= at) {
1238 nframes64_t new_pos = (*i)->position() + distance;
1241 } else if (new_pos >= max_frames - (*i)->length()) {
1242 new_pos = max_frames - (*i)->length();
1245 (*i)->set_position (new_pos, this);
1251 notify_length_changed ();
1255 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1257 if (in_set_state || _splicing || _nudging || _shuffling) {
1261 if (what_changed & ARDOUR::PositionChanged) {
1263 /* remove it from the list then add it back in
1264 the right place again.
1267 RegionSortByPosition cmp;
1269 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1271 if (i == regions.end()) {
1272 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1273 _name, region->name())
1279 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1282 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1284 nframes64_t delta = 0;
1286 if (what_changed & ARDOUR::PositionChanged) {
1287 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1290 if (what_changed & ARDOUR::LengthChanged) {
1291 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1295 possibly_splice (region->last_position() + region->last_length(), delta, region);
1298 if (holding_state ()) {
1299 pending_bounds.push_back (region);
1301 if (_session.config.get_layer_model() == MoveAddHigher) {
1302 /* it moved or changed length, so change the timestamp */
1303 timestamp_layer_op (region);
1306 notify_length_changed ();
1308 check_dependents (region, false);
1314 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1316 boost::shared_ptr<Region> region (weak_region.lock());
1322 /* this makes a virtual call to the right kind of playlist ... */
1324 region_changed (what_changed, region);
1328 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1330 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1333 if (in_set_state || in_flush) {
1337 if (what_changed & BoundsChanged) {
1338 region_bounds_changed (what_changed, region);
1339 save = !(_splicing || _nudging);
1342 if ((what_changed & our_interests) &&
1343 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1344 check_dependents (region, false);
1347 if (what_changed & Change (ARDOUR::PositionChanged)) {
1348 notify_region_moved (region);
1351 if (what_changed & our_interests) {
1359 Playlist::drop_regions ()
1361 RegionLock rl (this);
1363 all_regions.clear ();
1367 Playlist::clear (bool with_signals)
1370 RegionLock rl (this);
1372 region_state_changed_connections.drop_connections ();
1374 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1375 pending_removes.insert (*i);
1382 pending_length = false;
1384 pending_modified = false;
1390 /***********************************************************************
1392 **********************************************************************/
1394 Playlist::RegionList *
1395 Playlist::regions_at (nframes_t frame)
1398 RegionLock rlock (this);
1399 return find_regions_at (frame);
1402 boost::shared_ptr<Region>
1403 Playlist::top_region_at (nframes_t frame)
1406 RegionLock rlock (this);
1407 RegionList *rlist = find_regions_at (frame);
1408 boost::shared_ptr<Region> region;
1410 if (rlist->size()) {
1411 RegionSortByLayer cmp;
1413 region = rlist->back();
1420 boost::shared_ptr<Region>
1421 Playlist::top_unmuted_region_at (nframes_t frame)
1424 RegionLock rlock (this);
1425 RegionList *rlist = find_regions_at (frame);
1427 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1429 RegionList::iterator tmp = i;
1432 if ((*i)->muted()) {
1439 boost::shared_ptr<Region> region;
1441 if (rlist->size()) {
1442 RegionSortByLayer cmp;
1444 region = rlist->back();
1451 Playlist::RegionList*
1452 Playlist::regions_to_read (nframes_t start, nframes_t end)
1454 /* Caller must hold lock */
1456 RegionList covering;
1457 set<nframes_t> to_check;
1458 set<boost::shared_ptr<Region> > unique;
1461 to_check.insert (start);
1462 to_check.insert (end);
1464 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1466 /* find all/any regions that span start+end */
1468 switch ((*i)->coverage (start, end)) {
1472 case OverlapInternal:
1473 covering.push_back (*i);
1477 to_check.insert ((*i)->position());
1478 covering.push_back (*i);
1482 to_check.insert ((*i)->last_frame());
1483 covering.push_back (*i);
1486 case OverlapExternal:
1487 covering.push_back (*i);
1488 to_check.insert ((*i)->position());
1489 to_check.insert ((*i)->last_frame());
1493 /* don't go too far */
1495 if ((*i)->position() > end) {
1500 RegionList* rlist = new RegionList;
1502 /* find all the regions that cover each position .... */
1504 if (covering.size() == 1) {
1506 rlist->push_back (covering.front());
1510 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1514 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1516 if ((*x)->covers (*t)) {
1517 here.push_back (*x);
1521 RegionSortByLayer cmp;
1524 /* ... and get the top/transparent regions at "here" */
1526 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1530 if ((*c)->opaque()) {
1532 /* the other regions at this position are hidden by this one */
1539 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1540 rlist->push_back (*s);
1543 if (rlist->size() > 1) {
1544 /* now sort by time order */
1546 RegionSortByPosition cmp;
1554 Playlist::RegionList *
1555 Playlist::find_regions_at (nframes_t frame)
1557 /* Caller must hold lock */
1559 RegionList *rlist = new RegionList;
1561 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1562 if ((*i)->covers (frame)) {
1563 rlist->push_back (*i);
1570 Playlist::RegionList *
1571 Playlist::regions_touched (nframes_t start, nframes_t end)
1573 RegionLock rlock (this);
1574 RegionList *rlist = new RegionList;
1576 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1577 if ((*i)->coverage (start, end) != OverlapNone) {
1578 rlist->push_back (*i);
1586 Playlist::find_next_transient (nframes64_t from, int dir)
1588 RegionLock rlock (this);
1589 AnalysisFeatureList points;
1590 AnalysisFeatureList these_points;
1592 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1594 if ((*i)->last_frame() < from) {
1598 if ((*i)->first_frame() > from) {
1603 (*i)->get_transients (these_points);
1605 /* add first frame, just, err, because */
1607 these_points.push_back ((*i)->first_frame());
1609 points.insert (points.end(), these_points.begin(), these_points.end());
1610 these_points.clear ();
1613 if (points.empty()) {
1617 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1618 bool reached = false;
1621 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1626 if (reached && (*x) > from) {
1631 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1636 if (reached && (*x) < from) {
1645 boost::shared_ptr<Region>
1646 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1648 RegionLock rlock (this);
1649 boost::shared_ptr<Region> ret;
1650 nframes_t closest = max_frames;
1652 bool end_iter = false;
1654 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1659 boost::shared_ptr<Region> r = (*i);
1664 pos = r->first_frame ();
1667 pos = r->last_frame ();
1670 pos = r->sync_position ();
1671 // r->adjust_to_sync (r->first_frame());
1676 case 1: /* forwards */
1679 if ((distance = pos - frame) < closest) {
1688 default: /* backwards */
1691 if ((distance = frame - pos) < closest) {
1708 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1710 RegionLock rlock (this);
1712 nframes64_t closest = max_frames;
1713 nframes64_t ret = -1;
1717 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1719 boost::shared_ptr<Region> r = (*i);
1720 nframes64_t distance;
1722 if (r->first_frame() > frame) {
1724 distance = r->first_frame() - frame;
1726 if (distance < closest) {
1727 ret = r->first_frame();
1732 if (r->last_frame () > frame) {
1734 distance = r->last_frame () - frame;
1736 if (distance < closest) {
1737 ret = r->last_frame ();
1745 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1747 boost::shared_ptr<Region> r = (*i);
1748 nframes64_t distance;
1750 if (r->last_frame() < frame) {
1752 distance = frame - r->last_frame();
1754 if (distance < closest) {
1755 ret = r->last_frame();
1760 if (r->first_frame() < frame) {
1762 distance = frame - r->first_frame();
1764 if (distance < closest) {
1765 ret = r->first_frame();
1775 /***********************************************************************/
1781 Playlist::mark_session_dirty ()
1783 if (!in_set_state && !holding_state ()) {
1784 _session.set_dirty();
1789 Playlist::set_state (const XMLNode& node, int version)
1793 XMLNodeConstIterator niter;
1794 XMLPropertyList plist;
1795 XMLPropertyConstIterator piter;
1797 boost::shared_ptr<Region> region;
1802 if (node.name() != "Playlist") {
1809 plist = node.properties();
1811 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1815 if (prop->name() == X_("name")) {
1816 _name = prop->value();
1817 } else if (prop->name() == X_("orig_diskstream_id")) {
1818 _orig_diskstream_id = prop->value ();
1819 } else if (prop->name() == X_("frozen")) {
1820 _frozen = string_is_affirmative (prop->value());
1826 nlist = node.children();
1828 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1832 if (child->name() == "Region") {
1834 if ((prop = child->property ("id")) == 0) {
1835 error << _("region state node has no ID, ignored") << endmsg;
1839 ID id = prop->value ();
1841 if ((region = region_by_id (id))) {
1843 Change what_changed = Change (0);
1845 if (region->set_live_state (*child, version, what_changed, true)) {
1846 error << _("Playlist: cannot reset region state from XML") << endmsg;
1850 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1851 error << _("Playlist: cannot create region from XML") << endmsg;
1855 add_region (region, region->position(), 1.0);
1857 // So that layer_op ordering doesn't get screwed up
1858 region->set_last_layer_op( region->layer());
1867 /* update dependents, which was not done during add_region_internal
1868 due to in_set_state being true
1871 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1872 check_dependents (*r, false);
1876 first_set_state = false;
1881 Playlist::get_state()
1883 return state (true);
1887 Playlist::get_template()
1889 return state (false);
1892 /** @param full_state true to include regions in the returned state, otherwise false.
1895 Playlist::state (bool full_state)
1897 XMLNode *node = new XMLNode (X_("Playlist"));
1900 node->add_property (X_("name"), _name);
1901 node->add_property (X_("type"), _type.to_string());
1903 _orig_diskstream_id.print (buf, sizeof (buf));
1904 node->add_property (X_("orig_diskstream_id"), buf);
1905 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1908 RegionLock rlock (this, false);
1909 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1910 node->add_child_nocopy ((*i)->get_state());
1915 node->add_child_copy (*_extra_xml);
1922 Playlist::empty() const
1924 RegionLock rlock (const_cast<Playlist *>(this), false);
1925 return regions.empty();
1929 Playlist::n_regions() const
1931 RegionLock rlock (const_cast<Playlist *>(this), false);
1932 return regions.size();
1936 Playlist::get_maximum_extent () const
1938 RegionLock rlock (const_cast<Playlist *>(this), false);
1939 return _get_maximum_extent ();
1943 Playlist::_get_maximum_extent () const
1945 RegionList::const_iterator i;
1946 nframes_t max_extent = 0;
1949 for (i = regions.begin(); i != regions.end(); ++i) {
1950 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1959 Playlist::bump_name (string name, Session &session)
1961 string newname = name;
1964 newname = bump_name_once (newname);
1965 } while (session.playlists->by_name (newname)!=NULL);
1972 Playlist::top_layer() const
1974 RegionLock rlock (const_cast<Playlist *> (this));
1977 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1978 top = max (top, (*i)->layer());
1984 Playlist::set_edit_mode (EditMode mode)
1989 /********************
1991 ********************/
1994 Playlist::relayer ()
1996 /* don't send multiple Modified notifications
1997 when multiple regions are relayered.
2002 /* Build up a new list of regions on each layer, stored in a set of lists
2003 each of which represent some period of time on some layer. The idea
2004 is to avoid having to search the entire region list to establish whether
2005 each region overlaps another */
2007 /* how many pieces to divide this playlist's time up into */
2008 int const divisions = 512;
2010 /* find the start and end positions of the regions on this playlist */
2011 nframes_t start = UINT_MAX;
2013 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2014 start = min (start, (*i)->position());
2015 end = max (end, (*i)->position() + (*i)->length());
2018 /* hence the size of each time division */
2019 double const division_size = (end - start) / double (divisions);
2021 vector<vector<RegionList> > layers;
2022 layers.push_back (vector<RegionList> (divisions));
2024 /* we want to go through regions from desired lowest to desired highest layer,
2025 which depends on the layer model
2028 RegionList copy = regions;
2030 /* sort according to the model and the layering mode that we're in */
2032 if (_explicit_relayering) {
2034 copy.sort (RegionSortByLayerWithPending ());
2036 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2038 copy.sort (RegionSortByLastLayerOp ());
2042 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2044 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2045 (*i)->set_pending_explicit_relayer (false);
2047 /* find the time divisions that this region covers */
2048 int const start_division = floor ( ((*i)->position() - start) / division_size);
2049 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2050 if (end_division == divisions) {
2054 assert (end_division < divisions);
2056 /* find the lowest layer that this region can go on */
2057 size_t j = layers.size();
2059 /* try layer j - 1; it can go on if it overlaps no other region
2060 that is already on that layer
2063 bool overlap = false;
2064 for (int k = start_division; k <= end_division; ++k) {
2065 RegionList::iterator l = layers[j-1][k].begin ();
2066 while (l != layers[j-1][k].end()) {
2067 if ((*l)->overlap_equivalent (*i)) {
2080 /* overlap, so we must use layer j */
2087 if (j == layers.size()) {
2088 /* we need a new layer for this region */
2089 layers.push_back (vector<RegionList> (divisions));
2092 /* put a reference to this region in each of the divisions that it exists in */
2093 for (int k = start_division; k <= end_division; ++k) {
2094 layers[j][k].push_back (*i);
2097 (*i)->set_layer (j);
2100 /* sending Modified means that various kinds of layering
2101 models operate correctly at the GUI
2102 level. slightly inefficient, but only slightly.
2104 We force a Modified signal here in case no layers actually
2113 /* XXX these layer functions are all deprecated */
2116 Playlist::raise_region (boost::shared_ptr<Region> region)
2118 uint32_t rsz = regions.size();
2119 layer_t target = region->layer() + 1U;
2121 if (target >= rsz) {
2122 /* its already at the effective top */
2126 move_region_to_layer (target, region, 1);
2130 Playlist::lower_region (boost::shared_ptr<Region> region)
2132 if (region->layer() == 0) {
2133 /* its already at the bottom */
2137 layer_t target = region->layer() - 1U;
2139 move_region_to_layer (target, region, -1);
2143 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2145 /* does nothing useful if layering mode is later=higher */
2146 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2147 (_session.config.get_layer_model() == AddHigher)) {
2148 timestamp_layer_op (region);
2154 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2156 /* does nothing useful if layering mode is later=higher */
2157 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2158 (_session.config.get_layer_model() == AddHigher)) {
2159 region->set_last_layer_op (0);
2165 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2167 RegionList::iterator i;
2168 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2169 list<LayerInfo> layerinfo;
2173 RegionLock rlock (const_cast<Playlist *> (this));
2175 for (i = regions.begin(); i != regions.end(); ++i) {
2183 /* region is moving up, move all regions on intermediate layers
2187 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2188 dest = (*i)->layer() - 1;
2195 /* region is moving down, move all regions on intermediate layers
2199 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2200 dest = (*i)->layer() + 1;
2210 newpair.second = dest;
2212 layerinfo.push_back (newpair);
2216 /* now reset the layers without holding the region lock */
2218 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2219 x->first->set_layer (x->second);
2222 region->set_layer (target_layer);
2225 /* now check all dependents */
2227 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2228 check_dependents (x->first, false);
2231 check_dependents (region, false);
2238 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2240 RegionList::iterator i;
2247 RegionLock rlock (const_cast<Playlist *> (this));
2249 for (i = regions.begin(); i != regions.end(); ++i) {
2251 if ((*i)->position() >= start) {
2255 if ((*i)->last_frame() > max_frames - distance) {
2256 new_pos = max_frames - (*i)->length();
2258 new_pos = (*i)->position() + distance;
2263 if ((*i)->position() > distance) {
2264 new_pos = (*i)->position() - distance;
2270 (*i)->set_position (new_pos, this);
2278 notify_length_changed ();
2283 boost::shared_ptr<Region>
2284 Playlist::find_region (const ID& id) const
2286 RegionLock rlock (const_cast<Playlist*> (this));
2288 /* searches all regions currently in use by the playlist */
2290 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2291 if ((*i)->id() == id) {
2296 return boost::shared_ptr<Region> ();
2299 boost::shared_ptr<Region>
2300 Playlist::region_by_id (ID id)
2302 /* searches all regions ever added to this playlist */
2304 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2305 if ((*i)->id() == id) {
2309 return boost::shared_ptr<Region> ();
2313 Playlist::dump () const
2315 boost::shared_ptr<Region> r;
2317 cerr << "Playlist \"" << _name << "\" " << endl
2318 << regions.size() << " regions "
2321 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2323 cerr << " " << r->name() << " ["
2324 << r->start() << "+" << r->length()
2334 Playlist::set_frozen (bool yn)
2340 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2342 // struct timeval tv;
2343 // gettimeofday (&tv, 0);
2344 region->set_last_layer_op (++layer_op_counter);
2349 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2354 if (region->locked()) {
2361 RegionLock rlock (const_cast<Playlist*> (this));
2366 RegionList::iterator next;
2368 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2369 if ((*i) == region) {
2373 if (next != regions.end()) {
2375 if ((*next)->locked()) {
2379 if ((*next)->position() != region->last_frame() + 1) {
2380 /* they didn't used to touch, so after shuffle,
2381 just have them swap positions.
2383 new_pos = (*next)->position();
2385 /* they used to touch, so after shuffle,
2386 make sure they still do. put the earlier
2387 region where the later one will end after
2390 new_pos = region->position() + (*next)->length();
2393 (*next)->set_position (region->position(), this);
2394 region->set_position (new_pos, this);
2396 /* avoid a full sort */
2398 regions.erase (i); // removes the region from the list */
2400 regions.insert (next, region); // adds it back after next
2409 RegionList::iterator prev = regions.end();
2411 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2412 if ((*i) == region) {
2414 if (prev != regions.end()) {
2416 if ((*prev)->locked()) {
2420 if (region->position() != (*prev)->last_frame() + 1) {
2421 /* they didn't used to touch, so after shuffle,
2422 just have them swap positions.
2424 new_pos = region->position();
2426 /* they used to touch, so after shuffle,
2427 make sure they still do. put the earlier
2428 one where the later one will end after
2430 new_pos = (*prev)->position() + region->length();
2433 region->set_position ((*prev)->position(), this);
2434 (*prev)->set_position (new_pos, this);
2436 /* avoid a full sort */
2438 regions.erase (i); // remove region
2439 regions.insert (prev, region); // insert region before prev
2455 check_dependents (region, false);
2463 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2465 RegionLock rlock (const_cast<Playlist*> (this));
2467 if (regions.size() > 1) {
2475 Playlist::update_after_tempo_map_change ()
2477 RegionLock rlock (const_cast<Playlist*> (this));
2478 RegionList copy (regions);
2482 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2483 (*i)->update_position_after_tempo_map_change ();
2490 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2492 RegionLock rl (this, false);
2493 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2499 Playlist::set_explicit_relayering (bool e)
2501 if (e == false && _explicit_relayering == true) {
2503 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2504 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2505 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2506 at this point would keep regions on the same layers.
2508 From then on in, it's just you and your towel.
2511 RegionLock rl (this);
2512 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2513 (*i)->set_last_layer_op ((*i)->layer ());
2517 _explicit_relayering = e;
2522 Playlist::has_region_at (nframes64_t const p) const
2524 RegionLock (const_cast<Playlist *> (this));
2526 RegionList::const_iterator i = regions.begin ();
2527 while (i != regions.end() && !(*i)->covers (p)) {
2531 return (i != regions.end());