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/debug.h"
36 #include "ardour/playlist.h"
37 #include "ardour/session.h"
38 #include "ardour/region.h"
39 #include "ardour/region_factory.h"
40 #include "ardour/playlist_factory.h"
41 #include "ardour/transient_detector.h"
42 #include "ardour/session_playlists.h"
47 using namespace ARDOUR;
50 struct ShowMeTheList {
51 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
53 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
55 boost::shared_ptr<Playlist> playlist;
59 struct RegionSortByLayer {
60 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
61 return a->layer() < b->layer();
65 struct RegionSortByLayerWithPending {
66 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
68 double p = a->layer ();
69 if (a->pending_explicit_relayer()) {
73 double q = b->layer ();
74 if (b->pending_explicit_relayer()) {
82 struct RegionSortByPosition {
83 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
84 return a->position() < b->position();
88 struct RegionSortByLastLayerOp {
89 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
90 return a->last_layer_op() < b->last_layer_op();
95 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
96 : SessionObject(sess, nom)
100 first_set_state = false;
105 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
106 : SessionObject(sess, "unnamed playlist")
109 const XMLProperty* prop = node.property("type");
110 assert(!prop || DataType(prop->value()) == _type);
113 _name = "unnamed"; /* reset by set_state */
115 /* set state called by derived class */
118 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
119 : SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
124 other->copy_regions (tmp);
128 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
129 add_region_internal( (*x), (*x)->position());
134 _splicing = other->_splicing;
135 _nudging = other->_nudging;
136 _edit_mode = other->_edit_mode;
139 first_set_state = false;
141 in_partition = false;
143 _read_data_count = 0;
144 _frozen = other->_frozen;
146 layer_op_counter = other->layer_op_counter;
147 freeze_length = other->freeze_length;
150 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
151 : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
153 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
155 nframes_t end = start + cnt - 1;
161 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
163 boost::shared_ptr<Region> region;
164 boost::shared_ptr<Region> new_region;
165 nframes_t offset = 0;
166 nframes_t position = 0;
173 overlap = region->coverage (start, end);
179 case OverlapInternal:
180 offset = start - region->position();
187 position = region->position() - start;
188 len = end - region->position();
192 offset = start - region->position();
194 len = region->length() - offset;
197 case OverlapExternal:
199 position = region->position() - start;
200 len = region->length();
204 _session.region_name (new_name, region->name(), false);
206 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
208 add_region_internal (new_region, position);
212 first_set_state = false;
214 /* this constructor does NOT notify others (session) */
221 InUse (true); /* EMIT SIGNAL */
232 InUse (false); /* EMIT SIGNAL */
237 Playlist::copy_regions (RegionList& newlist) const
239 RegionLock rlock (const_cast<Playlist *> (this));
241 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
242 newlist.push_back (RegionFactory::RegionFactory::create (*i));
247 Playlist::init (bool hide)
249 g_atomic_int_set (&block_notifications, 0);
250 g_atomic_int_set (&ignore_state_changes, 0);
251 pending_modified = false;
252 pending_length = false;
253 first_set_state = true;
260 _edit_mode = Config->get_edit_mode();
262 in_partition = false;
264 _read_data_count = 0;
266 layer_op_counter = 0;
268 _explicit_relayering = false;
270 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
273 Playlist::~Playlist ()
275 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
277 RegionLock rl (this);
279 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
280 (*i)->set_playlist (boost::shared_ptr<Playlist>());
284 /* GoingAway must be emitted by derived classes */
288 Playlist::set_name (const string& str)
290 /* in a typical situation, a playlist is being used
291 by one diskstream and also is referenced by the
292 Session. if there are more references than that,
293 then don't change the name.
299 return SessionObject::set_name(str);
303 /***********************************************************************
304 CHANGE NOTIFICATION HANDLING
306 Notifications must be delayed till the region_lock is released. This
307 is necessary because handlers for the signals may need to acquire
308 the lock (e.g. to read from the playlist).
309 ***********************************************************************/
314 delay_notifications ();
315 g_atomic_int_inc (&ignore_state_changes);
321 g_atomic_int_dec_and_test (&ignore_state_changes);
322 release_notifications ();
327 Playlist::delay_notifications ()
329 g_atomic_int_inc (&block_notifications);
330 freeze_length = _get_maximum_extent();
334 Playlist::release_notifications ()
336 if (g_atomic_int_dec_and_test (&block_notifications)) {
337 flush_notifications ();
342 Playlist::notify_modified ()
344 if (holding_state ()) {
345 pending_modified = true;
347 pending_modified = false;
348 Modified(); /* EMIT SIGNAL */
353 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
355 if (holding_state ()) {
356 pending_removes.insert (r);
357 pending_modified = true;
358 pending_length = true;
360 /* this might not be true, but we have to act
361 as though it could be.
363 pending_length = false;
364 LengthChanged (); /* EMIT SIGNAL */
365 pending_modified = false;
366 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
367 Modified (); /* EMIT SIGNAL */
372 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
374 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
376 if (holding_state ()) {
378 pending_range_moves.push_back (move);
382 list< Evoral::RangeMove<nframes_t> > m;
390 Playlist::notify_region_added (boost::shared_ptr<Region> r)
392 /* the length change might not be true, but we have to act
393 as though it could be.
396 if (holding_state()) {
397 pending_adds.insert (r);
398 pending_modified = true;
399 pending_length = true;
401 pending_length = false;
402 LengthChanged (); /* EMIT SIGNAL */
403 pending_modified = false;
404 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
405 Modified (); /* EMIT SIGNAL */
410 Playlist::notify_length_changed ()
412 if (holding_state ()) {
413 pending_length = true;
415 pending_length = false;
416 LengthChanged(); /* EMIT SIGNAL */
417 pending_modified = false;
418 Modified (); /* EMIT SIGNAL */
423 Playlist::flush_notifications ()
425 set<boost::shared_ptr<Region> > dependent_checks_needed;
426 set<boost::shared_ptr<Region> >::iterator s;
435 /* we have no idea what order the regions ended up in pending
436 bounds (it could be based on selection order, for example).
437 so, to preserve layering in the "most recently moved is higher"
438 model, sort them by existing layer, then timestamp them.
441 // RegionSortByLayer cmp;
442 // pending_bounds.sort (cmp);
444 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
445 if (_session.config.get_layer_model() == MoveAddHigher) {
446 timestamp_layer_op (*r);
449 pending_length = true;
450 dependent_checks_needed.insert (*r);
455 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
456 remove_dependents (*s);
457 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
461 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
462 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
463 dependent_checks_needed.insert (*s);
467 if ((freeze_length != _get_maximum_extent()) || pending_length) {
469 LengthChanged(); /* EMIT SIGNAL */
473 if (n || pending_modified) {
477 pending_modified = false;
478 Modified (); /* EMIT SIGNAL */
481 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
482 check_dependents (*s, false);
485 if (!pending_range_moves.empty ()) {
486 RangesMoved (pending_range_moves);
489 pending_adds.clear ();
490 pending_removes.clear ();
491 pending_bounds.clear ();
492 pending_range_moves.clear ();
497 /*************************************************************
499 *************************************************************/
502 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
504 RegionLock rlock (this);
505 times = fabs (times);
507 int itimes = (int) floor (times);
509 nframes_t pos = position;
511 if (times == 1 && auto_partition){
512 partition(pos, (nframes_t) (pos + region->length()), true);
516 add_region_internal (region, pos);
517 pos += region->length();
522 /* note that itimes can be zero if we being asked to just
523 insert a single fraction of the region.
526 for (int i = 0; i < itimes; ++i) {
527 boost::shared_ptr<Region> copy = RegionFactory::create (region);
528 add_region_internal (copy, pos);
529 pos += region->length();
532 nframes_t length = 0;
534 if (floor (times) != times) {
535 length = (nframes_t) floor (region->length() * (times - floor (times)));
537 _session.region_name (name, region->name(), false);
538 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
539 add_region_internal (sub, pos);
542 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
546 Playlist::set_region_ownership ()
548 RegionLock rl (this);
549 RegionList::iterator i;
550 boost::weak_ptr<Playlist> pl (shared_from_this());
552 for (i = regions.begin(); i != regions.end(); ++i) {
553 (*i)->set_playlist (pl);
558 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
560 if (region->data_type() != _type){
564 RegionSortByPosition cmp;
566 nframes_t old_length = 0;
568 if (!holding_state()) {
569 old_length = _get_maximum_extent();
572 if (!first_set_state) {
573 boost::shared_ptr<Playlist> foo (shared_from_this());
574 region->set_playlist (boost::weak_ptr<Playlist>(foo));
577 region->set_position (position, this);
579 timestamp_layer_op (region);
581 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
582 all_regions.insert (region);
584 possibly_splice_unlocked (position, region->length(), region);
586 if (!holding_state () && !in_set_state) {
587 /* layers get assigned from XML state */
591 /* we need to notify the existence of new region before checking dependents. Ick. */
593 notify_region_added (region);
595 if (!holding_state ()) {
597 check_dependents (region, false);
599 if (old_length != _get_maximum_extent()) {
600 notify_length_changed ();
604 region_state_changed_connections.push_back (
605 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
606 boost::weak_ptr<Region> (region)))
613 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
615 RegionLock rlock (this);
617 bool old_sp = _splicing;
620 remove_region_internal (old);
621 add_region_internal (newr, pos);
625 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
629 Playlist::remove_region (boost::shared_ptr<Region> region)
631 RegionLock rlock (this);
632 remove_region_internal (region);
636 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
638 RegionList::iterator i;
639 nframes_t old_length = 0;
641 if (!holding_state()) {
642 old_length = _get_maximum_extent();
647 region->set_playlist (boost::weak_ptr<Playlist>());
650 for (i = regions.begin(); i != regions.end(); ++i) {
653 nframes_t pos = (*i)->position();
654 nframes64_t distance = (*i)->length();
658 possibly_splice_unlocked (pos, -distance);
660 if (!holding_state ()) {
662 remove_dependents (region);
664 if (old_length != _get_maximum_extent()) {
665 notify_length_changed ();
669 notify_region_removed (region);
680 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
682 if (Config->get_use_overlap_equivalency()) {
683 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
684 if ((*i)->overlap_equivalent (other)) {
685 results.push_back ((*i));
689 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
690 if ((*i)->equivalent (other)) {
691 results.push_back ((*i));
698 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
700 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
702 if ((*i) && (*i)->region_list_equivalent (other)) {
703 results.push_back (*i);
709 Playlist::partition (nframes_t start, nframes_t end, bool cut)
713 partition_internal (start, end, cut, thawlist);
715 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
716 (*i)->thaw ("separation");
721 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
723 RegionList new_regions;
726 RegionLock rlock (this);
728 boost::shared_ptr<Region> region;
729 boost::shared_ptr<Region> current;
731 RegionList::iterator tmp;
733 nframes_t pos1, pos2, pos3, pos4;
737 /* need to work from a copy, because otherwise the regions we add during the process
738 get operated on as well.
741 RegionList copy = regions;
743 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
750 if (current->first_frame() >= start && current->last_frame() < end) {
753 remove_region_internal (current);
759 /* coverage will return OverlapStart if the start coincides
760 with the end point. we do not partition such a region,
761 so catch this special case.
764 if (current->first_frame() >= end) {
768 if ((overlap = current->coverage (start, end)) == OverlapNone) {
772 pos1 = current->position();
775 pos4 = current->last_frame();
777 if (overlap == OverlapInternal) {
778 /* split: we need 3 new regions, the front, middle and end.
779 cut: we need 2 regions, the front and end.
784 ---------------*************************------------
787 ---------------*****++++++++++++++++====------------
789 ---------------*****----------------====------------
794 /* "middle" ++++++ */
796 _session.region_name (new_name, current->name(), false);
797 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
798 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
799 add_region_internal (region, start);
800 new_regions.push_back (region);
805 _session.region_name (new_name, current->name(), false);
806 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
807 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
809 add_region_internal (region, end);
810 new_regions.push_back (region);
815 thawlist.push_back (current);
816 current->trim_end (pos2, this);
818 } else if (overlap == OverlapEnd) {
822 ---------------*************************------------
825 ---------------**************+++++++++++------------
827 ---------------**************-----------------------
834 _session.region_name (new_name, current->name(), false);
835 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
836 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
838 add_region_internal (region, start);
839 new_regions.push_back (region);
845 thawlist.push_back (current);
846 current->trim_end (pos2, this);
848 } else if (overlap == OverlapStart) {
850 /* split: we need 2 regions: the front and the end.
851 cut: just trim current to skip the cut area
856 ---------------*************************------------
860 ---------------****+++++++++++++++++++++------------
862 -------------------*********************------------
868 _session.region_name (new_name, current->name(), false);
869 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
870 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
872 add_region_internal (region, pos1);
873 new_regions.push_back (region);
879 thawlist.push_back (current);
880 current->trim_front (pos3, this);
881 } else if (overlap == OverlapExternal) {
883 /* split: no split required.
884 cut: remove the region.
889 ---------------*************************------------
893 ---------------*************************------------
895 ----------------------------------------------------
900 remove_region_internal (current);
903 new_regions.push_back (current);
907 in_partition = false;
910 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
911 check_dependents (*i, false);
915 boost::shared_ptr<Playlist>
916 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
918 boost::shared_ptr<Playlist> ret;
919 boost::shared_ptr<Playlist> pl;
922 if (ranges.empty()) {
923 return boost::shared_ptr<Playlist>();
926 start = ranges.front().start;
928 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
930 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
932 if (i == ranges.begin()) {
936 /* paste the next section into the nascent playlist,
937 offset to reflect the start of the first range we
941 ret->paste (pl, (*i).start - start, 1.0f);
948 boost::shared_ptr<Playlist>
949 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
951 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
952 return cut_copy (pmf, ranges, result_is_hidden);
955 boost::shared_ptr<Playlist>
956 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
958 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
959 return cut_copy (pmf, ranges, result_is_hidden);
962 boost::shared_ptr<Playlist>
963 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
965 boost::shared_ptr<Playlist> the_copy;
969 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
970 string new_name = _name;
974 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
975 return boost::shared_ptr<Playlist>();
978 partition_internal (start, start+cnt-1, true, thawlist);
980 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
981 (*i)->thaw ("playlist cut");
987 boost::shared_ptr<Playlist>
988 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
992 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
993 string new_name = _name;
997 cnt = min (_get_maximum_extent() - start, cnt);
998 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1002 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
1004 times = fabs (times);
1005 nframes_t old_length;
1008 RegionLock rl1 (this);
1009 RegionLock rl2 (other.get());
1011 old_length = _get_maximum_extent();
1013 int itimes = (int) floor (times);
1014 nframes_t pos = position;
1015 nframes_t shift = other->_get_maximum_extent();
1016 layer_t top_layer = regions.size();
1019 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1020 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1022 /* put these new regions on top of all existing ones, but preserve
1023 the ordering they had in the original playlist.
1026 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1027 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1033 /* XXX shall we handle fractional cases at some point? */
1035 if (old_length != _get_maximum_extent()) {
1036 notify_length_changed ();
1047 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1049 times = fabs (times);
1051 RegionLock rl (this);
1052 int itimes = (int) floor (times);
1053 nframes_t pos = position;
1056 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1057 add_region_internal (copy, pos);
1058 pos += region->length();
1061 if (floor (times) != times) {
1062 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1064 _session.region_name (name, region->name(), false);
1065 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1066 add_region_internal (sub, pos);
1071 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1073 RegionLock rlock (this);
1074 RegionList copy (regions);
1077 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1079 if ((*r)->last_frame() < at) {
1084 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1085 /* intersected region */
1086 if (!move_intersected) {
1091 /* do not move regions glued to music time - that
1092 has to be done separately.
1095 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1096 fixup.push_back (*r);
1100 (*r)->set_position ((*r)->position() + distance, this);
1103 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1104 (*r)->recompute_position_from_lock_style ();
1109 Playlist::split (nframes64_t at)
1111 RegionLock rlock (this);
1112 RegionList copy (regions);
1114 /* use a copy since this operation can modify the region list
1117 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1118 _split_region (*r, at);
1123 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1125 RegionLock rl (this);
1126 _split_region (region, playlist_position);
1130 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1132 if (!region->covers (playlist_position)) {
1136 if (region->position() == playlist_position ||
1137 region->last_frame() == playlist_position) {
1141 boost::shared_ptr<Region> left;
1142 boost::shared_ptr<Region> right;
1148 /* split doesn't change anything about length, so don't try to splice */
1150 bool old_sp = _splicing;
1153 before = playlist_position - region->position();
1154 after = region->length() - before;
1156 _session.region_name (before_name, region->name(), false);
1157 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1159 _session.region_name (after_name, region->name(), false);
1160 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1162 add_region_internal (left, region->position());
1163 add_region_internal (right, region->position() + before);
1165 uint64_t orig_layer_op = region->last_layer_op();
1166 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1167 if ((*i)->last_layer_op() > orig_layer_op) {
1168 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1172 left->set_last_layer_op ( orig_layer_op );
1173 right->set_last_layer_op ( orig_layer_op + 1);
1177 finalize_split_region (region, left, right);
1179 remove_region_internal (region);
1185 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1187 if (_splicing || in_set_state) {
1188 /* don't respond to splicing moves or state setting */
1192 if (_edit_mode == Splice) {
1193 splice_locked (at, distance, exclude);
1198 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1200 if (_splicing || in_set_state) {
1201 /* don't respond to splicing moves or state setting */
1205 if (_edit_mode == Splice) {
1206 splice_unlocked (at, distance, exclude);
1211 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1214 RegionLock rl (this);
1215 core_splice (at, distance, exclude);
1220 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1222 core_splice (at, distance, exclude);
1226 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1230 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1232 if (exclude && (*i) == exclude) {
1236 if ((*i)->position() >= at) {
1237 nframes64_t new_pos = (*i)->position() + distance;
1240 } else if (new_pos >= max_frames - (*i)->length()) {
1241 new_pos = max_frames - (*i)->length();
1244 (*i)->set_position (new_pos, this);
1250 notify_length_changed ();
1254 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1256 if (in_set_state || _splicing || _nudging || _shuffling) {
1260 if (what_changed & ARDOUR::PositionChanged) {
1262 /* remove it from the list then add it back in
1263 the right place again.
1266 RegionSortByPosition cmp;
1268 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1270 if (i == regions.end()) {
1271 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1272 _name, region->name())
1278 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1281 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1283 nframes64_t delta = 0;
1285 if (what_changed & ARDOUR::PositionChanged) {
1286 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1289 if (what_changed & ARDOUR::LengthChanged) {
1290 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1294 possibly_splice (region->last_position() + region->last_length(), delta, region);
1297 if (holding_state ()) {
1298 pending_bounds.push_back (region);
1300 if (_session.config.get_layer_model() == MoveAddHigher) {
1301 /* it moved or changed length, so change the timestamp */
1302 timestamp_layer_op (region);
1305 notify_length_changed ();
1307 check_dependents (region, false);
1313 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1315 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);
1373 std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
1374 i != region_state_changed_connections.end ();
1380 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1381 pending_removes.insert (*i);
1388 pending_length = false;
1390 pending_modified = false;
1396 /***********************************************************************
1398 **********************************************************************/
1400 Playlist::RegionList *
1401 Playlist::regions_at (nframes_t frame)
1404 RegionLock rlock (this);
1405 return find_regions_at (frame);
1408 boost::shared_ptr<Region>
1409 Playlist::top_region_at (nframes_t frame)
1412 RegionLock rlock (this);
1413 RegionList *rlist = find_regions_at (frame);
1414 boost::shared_ptr<Region> region;
1416 if (rlist->size()) {
1417 RegionSortByLayer cmp;
1419 region = rlist->back();
1426 boost::shared_ptr<Region>
1427 Playlist::top_unmuted_region_at (nframes_t frame)
1430 RegionLock rlock (this);
1431 RegionList *rlist = find_regions_at (frame);
1433 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1435 RegionList::iterator tmp = i;
1438 if ((*i)->muted()) {
1445 boost::shared_ptr<Region> region;
1447 if (rlist->size()) {
1448 RegionSortByLayer cmp;
1450 region = rlist->back();
1457 Playlist::RegionList*
1458 Playlist::regions_to_read (nframes_t start, nframes_t end)
1460 /* Caller must hold lock */
1462 RegionList covering;
1463 set<nframes_t> to_check;
1464 set<boost::shared_ptr<Region> > unique;
1467 to_check.insert (start);
1468 to_check.insert (end);
1470 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1472 /* find all/any regions that span start+end */
1474 switch ((*i)->coverage (start, end)) {
1478 case OverlapInternal:
1479 covering.push_back (*i);
1483 to_check.insert ((*i)->position());
1484 covering.push_back (*i);
1488 to_check.insert ((*i)->last_frame());
1489 covering.push_back (*i);
1492 case OverlapExternal:
1493 covering.push_back (*i);
1494 to_check.insert ((*i)->position());
1495 to_check.insert ((*i)->last_frame());
1499 /* don't go too far */
1501 if ((*i)->position() > end) {
1506 RegionList* rlist = new RegionList;
1508 /* find all the regions that cover each position .... */
1510 if (covering.size() == 1) {
1512 rlist->push_back (covering.front());
1516 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1520 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1522 if ((*x)->covers (*t)) {
1523 here.push_back (*x);
1527 RegionSortByLayer cmp;
1530 /* ... and get the top/transparent regions at "here" */
1532 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1536 if ((*c)->opaque()) {
1538 /* the other regions at this position are hidden by this one */
1545 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1546 rlist->push_back (*s);
1549 if (rlist->size() > 1) {
1550 /* now sort by time order */
1552 RegionSortByPosition cmp;
1560 Playlist::RegionList *
1561 Playlist::find_regions_at (nframes_t frame)
1563 /* Caller must hold lock */
1565 RegionList *rlist = new RegionList;
1567 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1568 if ((*i)->covers (frame)) {
1569 rlist->push_back (*i);
1576 Playlist::RegionList *
1577 Playlist::regions_touched (nframes_t start, nframes_t end)
1579 RegionLock rlock (this);
1580 RegionList *rlist = new RegionList;
1582 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1583 if ((*i)->coverage (start, end) != OverlapNone) {
1584 rlist->push_back (*i);
1592 Playlist::find_next_transient (nframes64_t from, int dir)
1594 RegionLock rlock (this);
1595 AnalysisFeatureList points;
1596 AnalysisFeatureList these_points;
1598 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1600 if ((*i)->last_frame() < from) {
1604 if ((*i)->first_frame() > from) {
1609 (*i)->get_transients (these_points);
1611 /* add first frame, just, err, because */
1613 these_points.push_back ((*i)->first_frame());
1615 points.insert (points.end(), these_points.begin(), these_points.end());
1616 these_points.clear ();
1619 if (points.empty()) {
1623 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1624 bool reached = false;
1627 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1632 if (reached && (*x) > from) {
1637 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1642 if (reached && (*x) < from) {
1651 boost::shared_ptr<Region>
1652 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1654 RegionLock rlock (this);
1655 boost::shared_ptr<Region> ret;
1656 nframes_t closest = max_frames;
1658 bool end_iter = false;
1660 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1665 boost::shared_ptr<Region> r = (*i);
1670 pos = r->first_frame ();
1673 pos = r->last_frame ();
1676 pos = r->sync_position ();
1677 // r->adjust_to_sync (r->first_frame());
1682 case 1: /* forwards */
1685 if ((distance = pos - frame) < closest) {
1694 default: /* backwards */
1697 if ((distance = frame - pos) < closest) {
1714 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1716 RegionLock rlock (this);
1718 nframes64_t closest = max_frames;
1719 nframes64_t ret = -1;
1723 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1725 boost::shared_ptr<Region> r = (*i);
1726 nframes64_t distance;
1728 if (r->first_frame() > frame) {
1730 distance = r->first_frame() - frame;
1732 if (distance < closest) {
1733 ret = r->first_frame();
1738 if (r->last_frame () > frame) {
1740 distance = r->last_frame () - frame;
1742 if (distance < closest) {
1743 ret = r->last_frame ();
1751 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1753 boost::shared_ptr<Region> r = (*i);
1754 nframes64_t distance;
1756 if (r->last_frame() < frame) {
1758 distance = frame - r->last_frame();
1760 if (distance < closest) {
1761 ret = r->last_frame();
1766 if (r->first_frame() < frame) {
1768 distance = frame - r->first_frame();
1770 if (distance < closest) {
1771 ret = r->first_frame();
1781 /***********************************************************************/
1787 Playlist::mark_session_dirty ()
1789 if (!in_set_state && !holding_state ()) {
1790 _session.set_dirty();
1795 Playlist::set_state (const XMLNode& node, int version)
1799 XMLNodeConstIterator niter;
1800 XMLPropertyList plist;
1801 XMLPropertyConstIterator piter;
1803 boost::shared_ptr<Region> region;
1808 if (node.name() != "Playlist") {
1815 plist = node.properties();
1817 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1821 if (prop->name() == X_("name")) {
1822 _name = prop->value();
1823 } else if (prop->name() == X_("orig_diskstream_id")) {
1824 _orig_diskstream_id = prop->value ();
1825 } else if (prop->name() == X_("frozen")) {
1826 _frozen = string_is_affirmative (prop->value());
1832 nlist = node.children();
1834 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1838 if (child->name() == "Region") {
1840 if ((prop = child->property ("id")) == 0) {
1841 error << _("region state node has no ID, ignored") << endmsg;
1845 ID id = prop->value ();
1847 if ((region = region_by_id (id))) {
1849 Change what_changed = Change (0);
1851 if (region->set_live_state (*child, version, what_changed, true)) {
1852 error << _("Playlist: cannot reset region state from XML") << endmsg;
1856 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1857 error << _("Playlist: cannot create region from XML") << endmsg;
1861 add_region (region, region->position(), 1.0);
1863 // So that layer_op ordering doesn't get screwed up
1864 region->set_last_layer_op( region->layer());
1873 /* update dependents, which was not done during add_region_internal
1874 due to in_set_state being true
1877 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1878 check_dependents (*r, false);
1882 first_set_state = false;
1887 Playlist::get_state()
1889 return state (true);
1893 Playlist::get_template()
1895 return state (false);
1898 /** @param full_state true to include regions in the returned state, otherwise false.
1901 Playlist::state (bool full_state)
1903 XMLNode *node = new XMLNode (X_("Playlist"));
1906 node->add_property (X_("name"), _name);
1907 node->add_property (X_("type"), _type.to_string());
1909 _orig_diskstream_id.print (buf, sizeof (buf));
1910 node->add_property (X_("orig_diskstream_id"), buf);
1911 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1914 RegionLock rlock (this, false);
1915 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1916 node->add_child_nocopy ((*i)->get_state());
1921 node->add_child_copy (*_extra_xml);
1928 Playlist::empty() const
1930 RegionLock rlock (const_cast<Playlist *>(this), false);
1931 return regions.empty();
1935 Playlist::n_regions() const
1937 RegionLock rlock (const_cast<Playlist *>(this), false);
1938 return regions.size();
1942 Playlist::get_maximum_extent () const
1944 RegionLock rlock (const_cast<Playlist *>(this), false);
1945 return _get_maximum_extent ();
1949 Playlist::_get_maximum_extent () const
1951 RegionList::const_iterator i;
1952 nframes_t max_extent = 0;
1955 for (i = regions.begin(); i != regions.end(); ++i) {
1956 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1965 Playlist::bump_name (string name, Session &session)
1967 string newname = name;
1970 newname = bump_name_once (newname);
1971 } while (session.playlists->by_name (newname)!=NULL);
1978 Playlist::top_layer() const
1980 RegionLock rlock (const_cast<Playlist *> (this));
1983 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1984 top = max (top, (*i)->layer());
1990 Playlist::set_edit_mode (EditMode mode)
1995 /********************
1997 ********************/
2000 Playlist::relayer ()
2002 /* don't send multiple Modified notifications
2003 when multiple regions are relayered.
2008 /* Build up a new list of regions on each layer, stored in a set of lists
2009 each of which represent some period of time on some layer. The idea
2010 is to avoid having to search the entire region list to establish whether
2011 each region overlaps another */
2013 /* how many pieces to divide this playlist's time up into */
2014 int const divisions = 512;
2016 /* find the start and end positions of the regions on this playlist */
2017 nframes_t start = UINT_MAX;
2019 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2020 start = min (start, (*i)->position());
2021 end = max (end, (*i)->position() + (*i)->length());
2024 /* hence the size of each time division */
2025 double const division_size = (end - start) / double (divisions);
2027 vector<vector<RegionList> > layers;
2028 layers.push_back (vector<RegionList> (divisions));
2030 /* we want to go through regions from desired lowest to desired highest layer,
2031 which depends on the layer model
2034 RegionList copy = regions;
2036 /* sort according to the model and the layering mode that we're in */
2038 if (_explicit_relayering) {
2040 copy.sort (RegionSortByLayerWithPending ());
2042 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2044 copy.sort (RegionSortByLastLayerOp ());
2048 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2050 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2051 (*i)->set_pending_explicit_relayer (false);
2053 /* find the time divisions that this region covers */
2054 int const start_division = floor ( ((*i)->position() - start) / division_size);
2055 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2056 if (end_division == divisions) {
2060 assert (end_division < divisions);
2062 /* find the lowest layer that this region can go on */
2063 size_t j = layers.size();
2065 /* try layer j - 1; it can go on if it overlaps no other region
2066 that is already on that layer
2069 bool overlap = false;
2070 for (int k = start_division; k <= end_division; ++k) {
2071 RegionList::iterator l = layers[j-1][k].begin ();
2072 while (l != layers[j-1][k].end()) {
2073 if ((*l)->overlap_equivalent (*i)) {
2086 /* overlap, so we must use layer j */
2093 if (j == layers.size()) {
2094 /* we need a new layer for this region */
2095 layers.push_back (vector<RegionList> (divisions));
2098 /* put a reference to this region in each of the divisions that it exists in */
2099 for (int k = start_division; k <= end_division; ++k) {
2100 layers[j][k].push_back (*i);
2103 (*i)->set_layer (j);
2106 /* sending Modified means that various kinds of layering
2107 models operate correctly at the GUI
2108 level. slightly inefficient, but only slightly.
2110 We force a Modified signal here in case no layers actually
2119 /* XXX these layer functions are all deprecated */
2122 Playlist::raise_region (boost::shared_ptr<Region> region)
2124 uint32_t rsz = regions.size();
2125 layer_t target = region->layer() + 1U;
2127 if (target >= rsz) {
2128 /* its already at the effective top */
2132 move_region_to_layer (target, region, 1);
2136 Playlist::lower_region (boost::shared_ptr<Region> region)
2138 if (region->layer() == 0) {
2139 /* its already at the bottom */
2143 layer_t target = region->layer() - 1U;
2145 move_region_to_layer (target, region, -1);
2149 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2151 /* does nothing useful if layering mode is later=higher */
2152 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2153 (_session.config.get_layer_model() == AddHigher)) {
2154 timestamp_layer_op (region);
2160 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2162 /* does nothing useful if layering mode is later=higher */
2163 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2164 (_session.config.get_layer_model() == AddHigher)) {
2165 region->set_last_layer_op (0);
2171 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2173 RegionList::iterator i;
2174 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2175 list<LayerInfo> layerinfo;
2179 RegionLock rlock (const_cast<Playlist *> (this));
2181 for (i = regions.begin(); i != regions.end(); ++i) {
2189 /* region is moving up, move all regions on intermediate layers
2193 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2194 dest = (*i)->layer() - 1;
2201 /* region is moving down, move all regions on intermediate layers
2205 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2206 dest = (*i)->layer() + 1;
2216 newpair.second = dest;
2218 layerinfo.push_back (newpair);
2222 /* now reset the layers without holding the region lock */
2224 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2225 x->first->set_layer (x->second);
2228 region->set_layer (target_layer);
2231 /* now check all dependents */
2233 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2234 check_dependents (x->first, false);
2237 check_dependents (region, false);
2244 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2246 RegionList::iterator i;
2253 RegionLock rlock (const_cast<Playlist *> (this));
2255 for (i = regions.begin(); i != regions.end(); ++i) {
2257 if ((*i)->position() >= start) {
2261 if ((*i)->last_frame() > max_frames - distance) {
2262 new_pos = max_frames - (*i)->length();
2264 new_pos = (*i)->position() + distance;
2269 if ((*i)->position() > distance) {
2270 new_pos = (*i)->position() - distance;
2276 (*i)->set_position (new_pos, this);
2284 notify_length_changed ();
2289 boost::shared_ptr<Region>
2290 Playlist::find_region (const ID& id) const
2292 RegionLock rlock (const_cast<Playlist*> (this));
2294 /* searches all regions currently in use by the playlist */
2296 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2297 if ((*i)->id() == id) {
2302 return boost::shared_ptr<Region> ();
2305 boost::shared_ptr<Region>
2306 Playlist::region_by_id (ID id)
2308 /* searches all regions ever added to this playlist */
2310 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2311 if ((*i)->id() == id) {
2315 return boost::shared_ptr<Region> ();
2319 Playlist::dump () const
2321 boost::shared_ptr<Region> r;
2323 cerr << "Playlist \"" << _name << "\" " << endl
2324 << regions.size() << " regions "
2327 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2329 cerr << " " << r->name() << " ["
2330 << r->start() << "+" << r->length()
2340 Playlist::set_frozen (bool yn)
2346 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2348 // struct timeval tv;
2349 // gettimeofday (&tv, 0);
2350 region->set_last_layer_op (++layer_op_counter);
2355 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2360 if (region->locked()) {
2367 RegionLock rlock (const_cast<Playlist*> (this));
2372 RegionList::iterator next;
2374 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2375 if ((*i) == region) {
2379 if (next != regions.end()) {
2381 if ((*next)->locked()) {
2385 if ((*next)->position() != region->last_frame() + 1) {
2386 /* they didn't used to touch, so after shuffle,
2387 just have them swap positions.
2389 new_pos = (*next)->position();
2391 /* they used to touch, so after shuffle,
2392 make sure they still do. put the earlier
2393 region where the later one will end after
2396 new_pos = region->position() + (*next)->length();
2399 (*next)->set_position (region->position(), this);
2400 region->set_position (new_pos, this);
2402 /* avoid a full sort */
2404 regions.erase (i); // removes the region from the list */
2406 regions.insert (next, region); // adds it back after next
2415 RegionList::iterator prev = regions.end();
2417 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2418 if ((*i) == region) {
2420 if (prev != regions.end()) {
2422 if ((*prev)->locked()) {
2426 if (region->position() != (*prev)->last_frame() + 1) {
2427 /* they didn't used to touch, so after shuffle,
2428 just have them swap positions.
2430 new_pos = region->position();
2432 /* they used to touch, so after shuffle,
2433 make sure they still do. put the earlier
2434 one where the later one will end after
2436 new_pos = (*prev)->position() + region->length();
2439 region->set_position ((*prev)->position(), this);
2440 (*prev)->set_position (new_pos, this);
2442 /* avoid a full sort */
2444 regions.erase (i); // remove region
2445 regions.insert (prev, region); // insert region before prev
2461 check_dependents (region, false);
2469 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2471 RegionLock rlock (const_cast<Playlist*> (this));
2473 if (regions.size() > 1) {
2481 Playlist::update_after_tempo_map_change ()
2483 RegionLock rlock (const_cast<Playlist*> (this));
2484 RegionList copy (regions);
2488 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2489 (*i)->update_position_after_tempo_map_change ();
2496 Playlist::foreach_region (sigc::slot<void, boost::shared_ptr<Region> > s)
2498 RegionLock rl (this, false);
2499 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2505 Playlist::set_explicit_relayering (bool e)
2507 if (e == false && _explicit_relayering == true) {
2509 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2510 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2511 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2512 at this point would keep regions on the same layers.
2514 From then on in, it's just you and your towel.
2517 RegionLock rl (this);
2518 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2519 (*i)->set_last_layer_op ((*i)->layer ());
2523 _explicit_relayering = e;
2528 Playlist::has_region_at (nframes64_t const p) const
2530 RegionLock (const_cast<Playlist *> (this));
2532 RegionList::const_iterator i = regions.begin ();
2533 while (i != regions.end() && !(*i)->covers (p)) {
2537 return (i != regions.end());