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"
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), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
123 other->copy_regions (tmp);
127 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
128 add_region_internal( (*x), (*x)->position());
133 _splicing = other->_splicing;
134 _nudging = other->_nudging;
135 _edit_mode = other->_edit_mode;
138 first_set_state = false;
140 in_partition = false;
142 _read_data_count = 0;
143 _frozen = other->_frozen;
145 layer_op_counter = other->layer_op_counter;
146 freeze_length = other->freeze_length;
149 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
150 : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
152 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
154 nframes_t end = start + cnt - 1;
160 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
162 boost::shared_ptr<Region> region;
163 boost::shared_ptr<Region> new_region;
164 nframes_t offset = 0;
165 nframes_t position = 0;
172 overlap = region->coverage (start, end);
178 case OverlapInternal:
179 offset = start - region->position();
186 position = region->position() - start;
187 len = end - region->position();
191 offset = start - region->position();
193 len = region->length() - offset;
196 case OverlapExternal:
198 position = region->position() - start;
199 len = region->length();
203 _session.region_name (new_name, region->name(), false);
205 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
207 add_region_internal (new_region, position);
211 first_set_state = false;
213 /* this constructor does NOT notify others (session) */
220 InUse (true); /* EMIT SIGNAL */
231 InUse (false); /* EMIT SIGNAL */
236 Playlist::copy_regions (RegionList& newlist) const
238 RegionLock rlock (const_cast<Playlist *> (this));
240 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
241 newlist.push_back (RegionFactory::RegionFactory::create (*i));
246 Playlist::init (bool hide)
248 g_atomic_int_set (&block_notifications, 0);
249 g_atomic_int_set (&ignore_state_changes, 0);
250 pending_modified = false;
251 pending_length = false;
252 first_set_state = true;
259 _edit_mode = Config->get_edit_mode();
261 in_partition = false;
263 _read_data_count = 0;
265 layer_op_counter = 0;
267 _explicit_relayering = false;
269 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
272 Playlist::~Playlist ()
274 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
276 RegionLock rl (this);
278 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
279 (*i)->set_playlist (boost::shared_ptr<Playlist>());
283 /* GoingAway must be emitted by derived classes */
287 Playlist::set_name (const string& str)
289 /* in a typical situation, a playlist is being used
290 by one diskstream and also is referenced by the
291 Session. if there are more references than that,
292 then don't change the name.
298 return SessionObject::set_name(str);
302 /***********************************************************************
303 CHANGE NOTIFICATION HANDLING
305 Notifications must be delayed till the region_lock is released. This
306 is necessary because handlers for the signals may need to acquire
307 the lock (e.g. to read from the playlist).
308 ***********************************************************************/
313 delay_notifications ();
314 g_atomic_int_inc (&ignore_state_changes);
320 g_atomic_int_dec_and_test (&ignore_state_changes);
321 release_notifications ();
326 Playlist::delay_notifications ()
328 g_atomic_int_inc (&block_notifications);
329 freeze_length = _get_maximum_extent();
333 Playlist::release_notifications ()
335 if (g_atomic_int_dec_and_test (&block_notifications)) {
336 flush_notifications ();
341 Playlist::notify_modified ()
343 if (holding_state ()) {
344 pending_modified = true;
346 pending_modified = false;
347 Modified(); /* EMIT SIGNAL */
352 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
354 if (holding_state ()) {
355 pending_removes.insert (r);
356 pending_modified = true;
357 pending_length = true;
359 /* this might not be true, but we have to act
360 as though it could be.
362 pending_length = false;
363 LengthChanged (); /* EMIT SIGNAL */
364 pending_modified = false;
365 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
366 Modified (); /* EMIT SIGNAL */
371 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
373 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
375 if (holding_state ()) {
377 pending_range_moves.push_back (move);
381 list< Evoral::RangeMove<nframes_t> > m;
389 Playlist::notify_region_added (boost::shared_ptr<Region> r)
391 /* the length change might not be true, but we have to act
392 as though it could be.
395 if (holding_state()) {
396 pending_adds.insert (r);
397 pending_modified = true;
398 pending_length = true;
400 pending_length = false;
401 LengthChanged (); /* EMIT SIGNAL */
402 pending_modified = false;
403 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
404 Modified (); /* EMIT SIGNAL */
409 Playlist::notify_length_changed ()
411 if (holding_state ()) {
412 pending_length = true;
414 pending_length = false;
415 LengthChanged(); /* EMIT SIGNAL */
416 pending_modified = false;
417 Modified (); /* EMIT SIGNAL */
422 Playlist::flush_notifications ()
424 set<boost::shared_ptr<Region> > dependent_checks_needed;
425 set<boost::shared_ptr<Region> >::iterator s;
434 /* we have no idea what order the regions ended up in pending
435 bounds (it could be based on selection order, for example).
436 so, to preserve layering in the "most recently moved is higher"
437 model, sort them by existing layer, then timestamp them.
440 // RegionSortByLayer cmp;
441 // pending_bounds.sort (cmp);
443 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
444 if (_session.config.get_layer_model() == MoveAddHigher) {
445 timestamp_layer_op (*r);
448 pending_length = true;
449 dependent_checks_needed.insert (*r);
454 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
455 remove_dependents (*s);
456 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
460 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
461 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
462 dependent_checks_needed.insert (*s);
466 if ((freeze_length != _get_maximum_extent()) || pending_length) {
468 LengthChanged(); /* EMIT SIGNAL */
472 if (n || pending_modified) {
476 pending_modified = false;
477 Modified (); /* EMIT SIGNAL */
480 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
481 check_dependents (*s, false);
484 if (!pending_range_moves.empty ()) {
485 RangesMoved (pending_range_moves);
488 pending_adds.clear ();
489 pending_removes.clear ();
490 pending_bounds.clear ();
491 pending_range_moves.clear ();
496 /*************************************************************
498 *************************************************************/
501 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
503 RegionLock rlock (this);
504 times = fabs (times);
506 int itimes = (int) floor (times);
508 nframes_t pos = position;
510 if (times == 1 && auto_partition){
511 partition(pos, (nframes_t) (pos + region->length()), true);
515 add_region_internal (region, pos);
516 pos += region->length();
521 /* note that itimes can be zero if we being asked to just
522 insert a single fraction of the region.
525 for (int i = 0; i < itimes; ++i) {
526 boost::shared_ptr<Region> copy = RegionFactory::create (region);
527 add_region_internal (copy, pos);
528 pos += region->length();
531 nframes_t length = 0;
533 if (floor (times) != times) {
534 length = (nframes_t) floor (region->length() * (times - floor (times)));
536 _session.region_name (name, region->name(), false);
537 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
538 add_region_internal (sub, pos);
541 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
545 Playlist::set_region_ownership ()
547 RegionLock rl (this);
548 RegionList::iterator i;
549 boost::weak_ptr<Playlist> pl (shared_from_this());
551 for (i = regions.begin(); i != regions.end(); ++i) {
552 (*i)->set_playlist (pl);
557 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
559 if (region->data_type() != _type){
563 RegionSortByPosition cmp;
565 nframes_t old_length = 0;
567 if (!holding_state()) {
568 old_length = _get_maximum_extent();
571 if (!first_set_state) {
572 boost::shared_ptr<Playlist> foo (shared_from_this());
573 region->set_playlist (boost::weak_ptr<Playlist>(foo));
576 region->set_position (position, this);
578 timestamp_layer_op (region);
580 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
581 all_regions.insert (region);
583 possibly_splice_unlocked (position, region->length(), region);
585 if (!holding_state () && !in_set_state) {
586 /* layers get assigned from XML state */
590 /* we need to notify the existence of new region before checking dependents. Ick. */
592 notify_region_added (region);
594 if (!holding_state ()) {
596 check_dependents (region, false);
598 if (old_length != _get_maximum_extent()) {
599 notify_length_changed ();
603 region_state_changed_connections.push_back (
604 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
605 boost::weak_ptr<Region> (region)))
612 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
614 RegionLock rlock (this);
616 bool old_sp = _splicing;
619 remove_region_internal (old);
620 add_region_internal (newr, pos);
624 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
628 Playlist::remove_region (boost::shared_ptr<Region> region)
630 RegionLock rlock (this);
631 remove_region_internal (region);
635 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
637 RegionList::iterator i;
638 nframes_t old_length = 0;
640 if (!holding_state()) {
641 old_length = _get_maximum_extent();
646 region->set_playlist (boost::weak_ptr<Playlist>());
649 for (i = regions.begin(); i != regions.end(); ++i) {
652 nframes_t pos = (*i)->position();
653 nframes64_t distance = (*i)->length();
657 possibly_splice_unlocked (pos, -distance);
659 if (!holding_state ()) {
661 remove_dependents (region);
663 if (old_length != _get_maximum_extent()) {
664 notify_length_changed ();
668 notify_region_removed (region);
679 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
681 if (Config->get_use_overlap_equivalency()) {
682 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
683 if ((*i)->overlap_equivalent (other)) {
684 results.push_back ((*i));
688 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
689 if ((*i)->equivalent (other)) {
690 results.push_back ((*i));
697 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
699 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
701 if ((*i) && (*i)->region_list_equivalent (other)) {
702 results.push_back (*i);
708 Playlist::partition (nframes_t start, nframes_t end, bool cut)
712 partition_internal (start, end, cut, thawlist);
714 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
715 (*i)->thaw ("separation");
720 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
722 RegionList new_regions;
725 RegionLock rlock (this);
727 boost::shared_ptr<Region> region;
728 boost::shared_ptr<Region> current;
730 RegionList::iterator tmp;
732 nframes_t pos1, pos2, pos3, pos4;
736 /* need to work from a copy, because otherwise the regions we add during the process
737 get operated on as well.
740 RegionList copy = regions;
742 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
749 if (current->first_frame() >= start && current->last_frame() < end) {
752 remove_region_internal (current);
758 /* coverage will return OverlapStart if the start coincides
759 with the end point. we do not partition such a region,
760 so catch this special case.
763 if (current->first_frame() >= end) {
767 if ((overlap = current->coverage (start, end)) == OverlapNone) {
771 pos1 = current->position();
774 pos4 = current->last_frame();
776 if (overlap == OverlapInternal) {
777 /* split: we need 3 new regions, the front, middle and end.
778 cut: we need 2 regions, the front and end.
783 ---------------*************************------------
786 ---------------*****++++++++++++++++====------------
788 ---------------*****----------------====------------
793 /* "middle" ++++++ */
795 _session.region_name (new_name, current->name(), false);
796 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
797 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
798 add_region_internal (region, start);
799 new_regions.push_back (region);
804 _session.region_name (new_name, current->name(), false);
805 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
806 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
808 add_region_internal (region, end);
809 new_regions.push_back (region);
814 thawlist.push_back (current);
815 current->trim_end (pos2, this);
817 } else if (overlap == OverlapEnd) {
821 ---------------*************************------------
824 ---------------**************+++++++++++------------
826 ---------------**************-----------------------
833 _session.region_name (new_name, current->name(), false);
834 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
835 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
837 add_region_internal (region, start);
838 new_regions.push_back (region);
844 thawlist.push_back (current);
845 current->trim_end (pos2, this);
847 } else if (overlap == OverlapStart) {
849 /* split: we need 2 regions: the front and the end.
850 cut: just trim current to skip the cut area
855 ---------------*************************------------
859 ---------------****+++++++++++++++++++++------------
861 -------------------*********************------------
867 _session.region_name (new_name, current->name(), false);
868 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
869 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
871 add_region_internal (region, pos1);
872 new_regions.push_back (region);
878 thawlist.push_back (current);
879 current->trim_front (pos3, this);
880 } else if (overlap == OverlapExternal) {
882 /* split: no split required.
883 cut: remove the region.
888 ---------------*************************------------
892 ---------------*************************------------
894 ----------------------------------------------------
899 remove_region_internal (current);
902 new_regions.push_back (current);
906 in_partition = false;
909 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
910 check_dependents (*i, false);
914 boost::shared_ptr<Playlist>
915 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
917 boost::shared_ptr<Playlist> ret;
918 boost::shared_ptr<Playlist> pl;
921 if (ranges.empty()) {
922 return boost::shared_ptr<Playlist>();
925 start = ranges.front().start;
927 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
929 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
931 if (i == ranges.begin()) {
935 /* paste the next section into the nascent playlist,
936 offset to reflect the start of the first range we
940 ret->paste (pl, (*i).start - start, 1.0f);
947 boost::shared_ptr<Playlist>
948 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
950 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
951 return cut_copy (pmf, ranges, result_is_hidden);
954 boost::shared_ptr<Playlist>
955 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
957 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
958 return cut_copy (pmf, ranges, result_is_hidden);
961 boost::shared_ptr<Playlist>
962 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
964 boost::shared_ptr<Playlist> the_copy;
968 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
969 string new_name = _name;
973 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
974 return boost::shared_ptr<Playlist>();
977 partition_internal (start, start+cnt-1, true, thawlist);
979 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
980 (*i)->thaw ("playlist cut");
986 boost::shared_ptr<Playlist>
987 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
991 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
992 string new_name = _name;
996 cnt = min (_get_maximum_extent() - start, cnt);
997 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1001 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
1003 times = fabs (times);
1004 nframes_t old_length;
1007 RegionLock rl1 (this);
1008 RegionLock rl2 (other.get());
1010 old_length = _get_maximum_extent();
1012 int itimes = (int) floor (times);
1013 nframes_t pos = position;
1014 nframes_t shift = other->_get_maximum_extent();
1015 layer_t top_layer = regions.size();
1018 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1019 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1021 /* put these new regions on top of all existing ones, but preserve
1022 the ordering they had in the original playlist.
1025 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1026 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1032 /* XXX shall we handle fractional cases at some point? */
1034 if (old_length != _get_maximum_extent()) {
1035 notify_length_changed ();
1046 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1048 times = fabs (times);
1050 RegionLock rl (this);
1051 int itimes = (int) floor (times);
1052 nframes_t pos = position;
1055 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1056 add_region_internal (copy, pos);
1057 pos += region->length();
1060 if (floor (times) != times) {
1061 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1063 _session.region_name (name, region->name(), false);
1064 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1065 add_region_internal (sub, pos);
1070 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1072 RegionLock rlock (this);
1073 RegionList copy (regions);
1076 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1078 if ((*r)->last_frame() < at) {
1083 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1084 /* intersected region */
1085 if (!move_intersected) {
1090 /* do not move regions glued to music time - that
1091 has to be done separately.
1094 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1095 fixup.push_back (*r);
1099 (*r)->set_position ((*r)->position() + distance, this);
1102 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1103 (*r)->recompute_position_from_lock_style ();
1108 Playlist::split (nframes64_t at)
1110 RegionLock rlock (this);
1111 RegionList copy (regions);
1113 /* use a copy since this operation can modify the region list
1116 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1117 _split_region (*r, at);
1122 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1124 RegionLock rl (this);
1125 _split_region (region, playlist_position);
1129 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1131 if (!region->covers (playlist_position)) {
1135 if (region->position() == playlist_position ||
1136 region->last_frame() == playlist_position) {
1140 boost::shared_ptr<Region> left;
1141 boost::shared_ptr<Region> right;
1147 /* split doesn't change anything about length, so don't try to splice */
1149 bool old_sp = _splicing;
1152 before = playlist_position - region->position();
1153 after = region->length() - before;
1155 _session.region_name (before_name, region->name(), false);
1156 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1158 _session.region_name (after_name, region->name(), false);
1159 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1161 add_region_internal (left, region->position());
1162 add_region_internal (right, region->position() + before);
1164 uint64_t orig_layer_op = region->last_layer_op();
1165 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1166 if ((*i)->last_layer_op() > orig_layer_op) {
1167 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1171 left->set_last_layer_op ( orig_layer_op );
1172 right->set_last_layer_op ( orig_layer_op + 1);
1176 finalize_split_region (region, left, right);
1178 remove_region_internal (region);
1184 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1186 if (_splicing || in_set_state) {
1187 /* don't respond to splicing moves or state setting */
1191 if (_edit_mode == Splice) {
1192 splice_locked (at, distance, exclude);
1197 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1199 if (_splicing || in_set_state) {
1200 /* don't respond to splicing moves or state setting */
1204 if (_edit_mode == Splice) {
1205 splice_unlocked (at, distance, exclude);
1210 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1213 RegionLock rl (this);
1214 core_splice (at, distance, exclude);
1219 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1221 core_splice (at, distance, exclude);
1225 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1229 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1231 if (exclude && (*i) == exclude) {
1235 if ((*i)->position() >= at) {
1236 nframes64_t new_pos = (*i)->position() + distance;
1239 } else if (new_pos >= max_frames - (*i)->length()) {
1240 new_pos = max_frames - (*i)->length();
1243 (*i)->set_position (new_pos, this);
1249 notify_length_changed ();
1253 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1255 if (in_set_state || _splicing || _nudging || _shuffling) {
1259 if (what_changed & ARDOUR::PositionChanged) {
1261 /* remove it from the list then add it back in
1262 the right place again.
1265 RegionSortByPosition cmp;
1267 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1269 if (i == regions.end()) {
1270 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1271 _name, region->name())
1277 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1280 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1282 nframes64_t delta = 0;
1284 if (what_changed & ARDOUR::PositionChanged) {
1285 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1288 if (what_changed & ARDOUR::LengthChanged) {
1289 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1293 possibly_splice (region->last_position() + region->last_length(), delta, region);
1296 if (holding_state ()) {
1297 pending_bounds.push_back (region);
1299 if (_session.config.get_layer_model() == MoveAddHigher) {
1300 /* it moved or changed length, so change the timestamp */
1301 timestamp_layer_op (region);
1304 notify_length_changed ();
1306 check_dependents (region, false);
1312 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1314 boost::shared_ptr<Region> region (weak_region.lock());
1321 /* this makes a virtual call to the right kind of playlist ... */
1323 region_changed (what_changed, region);
1327 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1329 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1332 if (in_set_state || in_flush) {
1336 if (what_changed & BoundsChanged) {
1337 region_bounds_changed (what_changed, region);
1338 save = !(_splicing || _nudging);
1341 if ((what_changed & our_interests) &&
1342 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1343 check_dependents (region, false);
1346 if (what_changed & Change (ARDOUR::PositionChanged)) {
1347 notify_region_moved (region);
1350 if (what_changed & our_interests) {
1358 Playlist::drop_regions ()
1360 RegionLock rl (this);
1362 all_regions.clear ();
1366 Playlist::clear (bool with_signals)
1369 RegionLock rl (this);
1372 std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
1373 i != region_state_changed_connections.end ();
1379 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1380 pending_removes.insert (*i);
1387 pending_length = false;
1389 pending_modified = false;
1395 /***********************************************************************
1397 **********************************************************************/
1399 Playlist::RegionList *
1400 Playlist::regions_at (nframes_t frame)
1403 RegionLock rlock (this);
1404 return find_regions_at (frame);
1407 boost::shared_ptr<Region>
1408 Playlist::top_region_at (nframes_t frame)
1411 RegionLock rlock (this);
1412 RegionList *rlist = find_regions_at (frame);
1413 boost::shared_ptr<Region> region;
1415 if (rlist->size()) {
1416 RegionSortByLayer cmp;
1418 region = rlist->back();
1425 boost::shared_ptr<Region>
1426 Playlist::top_unmuted_region_at (nframes_t frame)
1429 RegionLock rlock (this);
1430 RegionList *rlist = find_regions_at (frame);
1432 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1434 RegionList::iterator tmp = i;
1437 if ((*i)->muted()) {
1444 boost::shared_ptr<Region> region;
1446 if (rlist->size()) {
1447 RegionSortByLayer cmp;
1449 region = rlist->back();
1456 Playlist::RegionList*
1457 Playlist::regions_to_read (nframes_t start, nframes_t end)
1459 /* Caller must hold lock */
1461 RegionList covering;
1462 set<nframes_t> to_check;
1463 set<boost::shared_ptr<Region> > unique;
1466 to_check.insert (start);
1467 to_check.insert (end);
1469 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1471 /* find all/any regions that span start+end */
1473 switch ((*i)->coverage (start, end)) {
1477 case OverlapInternal:
1478 covering.push_back (*i);
1482 to_check.insert ((*i)->position());
1483 covering.push_back (*i);
1487 to_check.insert ((*i)->last_frame());
1488 covering.push_back (*i);
1491 case OverlapExternal:
1492 covering.push_back (*i);
1493 to_check.insert ((*i)->position());
1494 to_check.insert ((*i)->last_frame());
1498 /* don't go too far */
1500 if ((*i)->position() > end) {
1505 RegionList* rlist = new RegionList;
1507 /* find all the regions that cover each position .... */
1509 if (covering.size() == 1) {
1511 rlist->push_back (covering.front());
1515 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1519 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1521 if ((*x)->covers (*t)) {
1522 here.push_back (*x);
1526 RegionSortByLayer cmp;
1529 /* ... and get the top/transparent regions at "here" */
1531 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1535 if ((*c)->opaque()) {
1537 /* the other regions at this position are hidden by this one */
1544 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1545 rlist->push_back (*s);
1548 if (rlist->size() > 1) {
1549 /* now sort by time order */
1551 RegionSortByPosition cmp;
1559 Playlist::RegionList *
1560 Playlist::find_regions_at (nframes_t frame)
1562 /* Caller must hold lock */
1564 RegionList *rlist = new RegionList;
1566 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1567 if ((*i)->covers (frame)) {
1568 rlist->push_back (*i);
1575 Playlist::RegionList *
1576 Playlist::regions_touched (nframes_t start, nframes_t end)
1578 RegionLock rlock (this);
1579 RegionList *rlist = new RegionList;
1581 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1582 if ((*i)->coverage (start, end) != OverlapNone) {
1583 rlist->push_back (*i);
1591 Playlist::find_next_transient (nframes64_t from, int dir)
1593 RegionLock rlock (this);
1594 AnalysisFeatureList points;
1595 AnalysisFeatureList these_points;
1597 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1599 if ((*i)->last_frame() < from) {
1603 if ((*i)->first_frame() > from) {
1608 (*i)->get_transients (these_points);
1610 /* add first frame, just, err, because */
1612 these_points.push_back ((*i)->first_frame());
1614 points.insert (points.end(), these_points.begin(), these_points.end());
1615 these_points.clear ();
1618 if (points.empty()) {
1622 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1623 bool reached = false;
1626 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1631 if (reached && (*x) > from) {
1636 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1641 if (reached && (*x) < from) {
1650 boost::shared_ptr<Region>
1651 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1653 RegionLock rlock (this);
1654 boost::shared_ptr<Region> ret;
1655 nframes_t closest = max_frames;
1657 bool end_iter = false;
1659 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1664 boost::shared_ptr<Region> r = (*i);
1669 pos = r->first_frame ();
1672 pos = r->last_frame ();
1675 pos = r->sync_position ();
1676 // r->adjust_to_sync (r->first_frame());
1681 case 1: /* forwards */
1684 if ((distance = pos - frame) < closest) {
1693 default: /* backwards */
1696 if ((distance = frame - pos) < closest) {
1713 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1715 RegionLock rlock (this);
1717 nframes64_t closest = max_frames;
1718 nframes64_t ret = -1;
1722 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1724 boost::shared_ptr<Region> r = (*i);
1725 nframes64_t distance;
1727 if (r->first_frame() > frame) {
1729 distance = r->first_frame() - frame;
1731 if (distance < closest) {
1732 ret = r->first_frame();
1737 if (r->last_frame () > frame) {
1739 distance = r->last_frame () - frame;
1741 if (distance < closest) {
1742 ret = r->last_frame ();
1750 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1752 boost::shared_ptr<Region> r = (*i);
1753 nframes64_t distance;
1755 if (r->last_frame() < frame) {
1757 distance = frame - r->last_frame();
1759 if (distance < closest) {
1760 ret = r->last_frame();
1765 if (r->first_frame() < frame) {
1767 distance = frame - r->first_frame();
1769 if (distance < closest) {
1770 ret = r->first_frame();
1780 /***********************************************************************/
1786 Playlist::mark_session_dirty ()
1788 if (!in_set_state && !holding_state ()) {
1789 _session.set_dirty();
1794 Playlist::set_state (const XMLNode& node, int version)
1798 XMLNodeConstIterator niter;
1799 XMLPropertyList plist;
1800 XMLPropertyConstIterator piter;
1802 boost::shared_ptr<Region> region;
1807 if (node.name() != "Playlist") {
1814 plist = node.properties();
1816 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1820 if (prop->name() == X_("name")) {
1821 _name = prop->value();
1822 } else if (prop->name() == X_("orig_diskstream_id")) {
1823 _orig_diskstream_id = prop->value ();
1824 } else if (prop->name() == X_("frozen")) {
1825 _frozen = string_is_affirmative (prop->value());
1831 nlist = node.children();
1833 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1837 if (child->name() == "Region") {
1839 if ((prop = child->property ("id")) == 0) {
1840 error << _("region state node has no ID, ignored") << endmsg;
1844 ID id = prop->value ();
1846 if ((region = region_by_id (id))) {
1848 Change what_changed = Change (0);
1850 if (region->set_live_state (*child, version, what_changed, true)) {
1851 error << _("Playlist: cannot reset region state from XML") << endmsg;
1855 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1856 error << _("Playlist: cannot create region from XML") << endmsg;
1860 add_region (region, region->position(), 1.0);
1862 // So that layer_op ordering doesn't get screwed up
1863 region->set_last_layer_op( region->layer());
1872 /* update dependents, which was not done during add_region_internal
1873 due to in_set_state being true
1876 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1877 check_dependents (*r, false);
1881 first_set_state = false;
1886 Playlist::get_state()
1888 return state (true);
1892 Playlist::get_template()
1894 return state (false);
1897 /** @param full_state true to include regions in the returned state, otherwise false.
1900 Playlist::state (bool full_state)
1902 XMLNode *node = new XMLNode (X_("Playlist"));
1905 node->add_property (X_("name"), _name);
1906 node->add_property (X_("type"), _type.to_string());
1908 _orig_diskstream_id.print (buf, sizeof (buf));
1909 node->add_property (X_("orig_diskstream_id"), buf);
1910 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1913 RegionLock rlock (this, false);
1914 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1915 node->add_child_nocopy ((*i)->get_state());
1920 node->add_child_copy (*_extra_xml);
1927 Playlist::empty() const
1929 RegionLock rlock (const_cast<Playlist *>(this), false);
1930 return regions.empty();
1934 Playlist::n_regions() const
1936 RegionLock rlock (const_cast<Playlist *>(this), false);
1937 return regions.size();
1941 Playlist::get_maximum_extent () const
1943 RegionLock rlock (const_cast<Playlist *>(this), false);
1944 return _get_maximum_extent ();
1948 Playlist::_get_maximum_extent () const
1950 RegionList::const_iterator i;
1951 nframes_t max_extent = 0;
1954 for (i = regions.begin(); i != regions.end(); ++i) {
1955 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1964 Playlist::bump_name (string name, Session &session)
1966 string newname = name;
1969 newname = bump_name_once (newname);
1970 } while (session.playlist_by_name (newname)!=NULL);
1977 Playlist::top_layer() const
1979 RegionLock rlock (const_cast<Playlist *> (this));
1982 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1983 top = max (top, (*i)->layer());
1989 Playlist::set_edit_mode (EditMode mode)
1994 /********************
1996 ********************/
1999 Playlist::relayer ()
2001 /* don't send multiple Modified notifications
2002 when multiple regions are relayered.
2007 /* Build up a new list of regions on each layer, stored in a set of lists
2008 each of which represent some period of time on some layer. The idea
2009 is to avoid having to search the entire region list to establish whether
2010 each region overlaps another */
2012 /* how many pieces to divide this playlist's time up into */
2013 int const divisions = 512;
2015 /* find the start and end positions of the regions on this playlist */
2016 nframes_t start = UINT_MAX;
2018 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2019 start = min (start, (*i)->position());
2020 end = max (end, (*i)->position() + (*i)->length());
2023 /* hence the size of each time division */
2024 double const division_size = (end - start) / double (divisions);
2026 vector<vector<RegionList> > layers;
2027 layers.push_back (vector<RegionList> (divisions));
2029 /* we want to go through regions from desired lowest to desired highest layer,
2030 which depends on the layer model
2033 RegionList copy = regions;
2035 /* sort according to the model and the layering mode that we're in */
2037 if (_explicit_relayering) {
2039 copy.sort (RegionSortByLayerWithPending ());
2041 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2043 copy.sort (RegionSortByLastLayerOp ());
2047 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2049 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2050 (*i)->set_pending_explicit_relayer (false);
2052 /* find the time divisions that this region covers */
2053 int const start_division = floor ( ((*i)->position() - start) / division_size);
2054 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2055 if (end_division == divisions) {
2059 assert (end_division < divisions);
2061 /* find the lowest layer that this region can go on */
2062 size_t j = layers.size();
2064 /* try layer j - 1; it can go on if it overlaps no other region
2065 that is already on that layer
2068 bool overlap = false;
2069 for (int k = start_division; k <= end_division; ++k) {
2070 RegionList::iterator l = layers[j-1][k].begin ();
2071 while (l != layers[j-1][k].end()) {
2072 if ((*l)->overlap_equivalent (*i)) {
2085 /* overlap, so we must use layer j */
2092 if (j == layers.size()) {
2093 /* we need a new layer for this region */
2094 layers.push_back (vector<RegionList> (divisions));
2097 /* put a reference to this region in each of the divisions that it exists in */
2098 for (int k = start_division; k <= end_division; ++k) {
2099 layers[j][k].push_back (*i);
2102 (*i)->set_layer (j);
2105 /* sending Modified means that various kinds of layering
2106 models operate correctly at the GUI
2107 level. slightly inefficient, but only slightly.
2109 We force a Modified signal here in case no layers actually
2118 /* XXX these layer functions are all deprecated */
2121 Playlist::raise_region (boost::shared_ptr<Region> region)
2123 uint32_t rsz = regions.size();
2124 layer_t target = region->layer() + 1U;
2126 if (target >= rsz) {
2127 /* its already at the effective top */
2131 move_region_to_layer (target, region, 1);
2135 Playlist::lower_region (boost::shared_ptr<Region> region)
2137 if (region->layer() == 0) {
2138 /* its already at the bottom */
2142 layer_t target = region->layer() - 1U;
2144 move_region_to_layer (target, region, -1);
2148 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2150 /* does nothing useful if layering mode is later=higher */
2151 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2152 (_session.config.get_layer_model() == AddHigher)) {
2153 timestamp_layer_op (region);
2159 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2161 /* does nothing useful if layering mode is later=higher */
2162 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2163 (_session.config.get_layer_model() == AddHigher)) {
2164 region->set_last_layer_op (0);
2170 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2172 RegionList::iterator i;
2173 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2174 list<LayerInfo> layerinfo;
2178 RegionLock rlock (const_cast<Playlist *> (this));
2180 for (i = regions.begin(); i != regions.end(); ++i) {
2188 /* region is moving up, move all regions on intermediate layers
2192 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2193 dest = (*i)->layer() - 1;
2200 /* region is moving down, move all regions on intermediate layers
2204 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2205 dest = (*i)->layer() + 1;
2215 newpair.second = dest;
2217 layerinfo.push_back (newpair);
2221 /* now reset the layers without holding the region lock */
2223 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2224 x->first->set_layer (x->second);
2227 region->set_layer (target_layer);
2230 /* now check all dependents */
2232 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2233 check_dependents (x->first, false);
2236 check_dependents (region, false);
2243 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2245 RegionList::iterator i;
2252 RegionLock rlock (const_cast<Playlist *> (this));
2254 for (i = regions.begin(); i != regions.end(); ++i) {
2256 if ((*i)->position() >= start) {
2260 if ((*i)->last_frame() > max_frames - distance) {
2261 new_pos = max_frames - (*i)->length();
2263 new_pos = (*i)->position() + distance;
2268 if ((*i)->position() > distance) {
2269 new_pos = (*i)->position() - distance;
2275 (*i)->set_position (new_pos, this);
2283 notify_length_changed ();
2288 boost::shared_ptr<Region>
2289 Playlist::find_region (const ID& id) const
2291 RegionLock rlock (const_cast<Playlist*> (this));
2293 /* searches all regions currently in use by the playlist */
2295 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2296 if ((*i)->id() == id) {
2301 return boost::shared_ptr<Region> ();
2304 boost::shared_ptr<Region>
2305 Playlist::region_by_id (ID id)
2307 /* searches all regions ever added to this playlist */
2309 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2310 if ((*i)->id() == id) {
2314 return boost::shared_ptr<Region> ();
2318 Playlist::dump () const
2320 boost::shared_ptr<Region> r;
2322 cerr << "Playlist \"" << _name << "\" " << endl
2323 << regions.size() << " regions "
2326 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2328 cerr << " " << r->name() << " ["
2329 << r->start() << "+" << r->length()
2339 Playlist::set_frozen (bool yn)
2345 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2347 // struct timeval tv;
2348 // gettimeofday (&tv, 0);
2349 region->set_last_layer_op (++layer_op_counter);
2354 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2359 if (region->locked()) {
2366 RegionLock rlock (const_cast<Playlist*> (this));
2371 RegionList::iterator next;
2373 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2374 if ((*i) == region) {
2378 if (next != regions.end()) {
2380 if ((*next)->locked()) {
2384 if ((*next)->position() != region->last_frame() + 1) {
2385 /* they didn't used to touch, so after shuffle,
2386 just have them swap positions.
2388 new_pos = (*next)->position();
2390 /* they used to touch, so after shuffle,
2391 make sure they still do. put the earlier
2392 region where the later one will end after
2395 new_pos = region->position() + (*next)->length();
2398 (*next)->set_position (region->position(), this);
2399 region->set_position (new_pos, this);
2401 /* avoid a full sort */
2403 regions.erase (i); // removes the region from the list */
2405 regions.insert (next, region); // adds it back after next
2414 RegionList::iterator prev = regions.end();
2416 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2417 if ((*i) == region) {
2419 if (prev != regions.end()) {
2421 if ((*prev)->locked()) {
2425 if (region->position() != (*prev)->last_frame() + 1) {
2426 /* they didn't used to touch, so after shuffle,
2427 just have them swap positions.
2429 new_pos = region->position();
2431 /* they used to touch, so after shuffle,
2432 make sure they still do. put the earlier
2433 one where the later one will end after
2435 new_pos = (*prev)->position() + region->length();
2438 region->set_position ((*prev)->position(), this);
2439 (*prev)->set_position (new_pos, this);
2441 /* avoid a full sort */
2443 regions.erase (i); // remove region
2444 regions.insert (prev, region); // insert region before prev
2460 check_dependents (region, false);
2468 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2470 RegionLock rlock (const_cast<Playlist*> (this));
2472 if (regions.size() > 1) {
2480 Playlist::update_after_tempo_map_change ()
2482 RegionLock rlock (const_cast<Playlist*> (this));
2483 RegionList copy (regions);
2487 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2488 (*i)->update_position_after_tempo_map_change ();
2495 Playlist::foreach_region (sigc::slot<void, boost::shared_ptr<Region> > s)
2497 RegionLock rl (this, false);
2498 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2504 Playlist::set_explicit_relayering (bool e)
2506 if (e == false && _explicit_relayering == true) {
2508 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2509 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2510 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2511 at this point would keep regions on the same layers.
2513 From then on in, it's just you and your towel.
2516 RegionLock rl (this);
2517 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2518 (*i)->set_last_layer_op ((*i)->layer ());
2522 _explicit_relayering = e;
2527 Playlist::has_region_at (nframes64_t const p) const
2529 RegionLock (const_cast<Playlist *> (this));
2531 RegionList::const_iterator i = regions.begin ();
2532 while (i != regions.end() && !(*i)->covers (p)) {
2536 return (i != regions.end());