2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sigc++/bind.h>
30 #include "pbd/failed_constructor.h"
31 #include "pbd/stl_delete.h"
32 #include "pbd/xml++.h"
33 #include "pbd/stacktrace.h"
35 #include "ardour/playlist.h"
36 #include "ardour/session.h"
37 #include "ardour/region.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/playlist_factory.h"
40 #include "ardour/transient_detector.h"
45 using namespace ARDOUR;
48 struct ShowMeTheList {
49 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
53 boost::shared_ptr<Playlist> playlist;
57 struct RegionSortByLayer {
58 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
59 return a->layer() < b->layer();
63 struct RegionSortByLayerWithPending {
64 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
66 double p = a->layer ();
67 if (a->pending_explicit_relayer()) {
71 double q = b->layer ();
72 if (b->pending_explicit_relayer()) {
80 struct RegionSortByPosition {
81 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
82 return a->position() < b->position();
86 struct RegionSortByLastLayerOp {
87 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
88 return a->last_layer_op() < b->last_layer_op();
93 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
94 : SessionObject(sess, nom)
98 first_set_state = false;
103 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
104 : SessionObject(sess, "unnamed playlist")
107 const XMLProperty* prop = node.property("type");
108 assert(!prop || DataType(prop->value()) == _type);
111 _name = "unnamed"; /* reset by set_state */
113 /* set state called by derived class */
116 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
117 : SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
122 other->copy_regions (tmp);
126 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
127 add_region_internal( (*x), (*x)->position());
132 _splicing = other->_splicing;
133 _nudging = other->_nudging;
134 _edit_mode = other->_edit_mode;
137 first_set_state = false;
139 in_partition = false;
141 _read_data_count = 0;
142 _frozen = other->_frozen;
144 layer_op_counter = other->layer_op_counter;
145 freeze_length = other->freeze_length;
148 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
149 : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
151 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
153 nframes_t end = start + cnt - 1;
159 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
161 boost::shared_ptr<Region> region;
162 boost::shared_ptr<Region> new_region;
163 nframes_t offset = 0;
164 nframes_t position = 0;
171 overlap = region->coverage (start, end);
177 case OverlapInternal:
178 offset = start - region->position();
185 position = region->position() - start;
186 len = end - region->position();
190 offset = start - region->position();
192 len = region->length() - offset;
195 case OverlapExternal:
197 position = region->position() - start;
198 len = region->length();
202 _session.region_name (new_name, region->name(), false);
204 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
206 add_region_internal (new_region, position);
210 first_set_state = false;
212 /* this constructor does NOT notify others (session) */
219 InUse (true); /* EMIT SIGNAL */
230 InUse (false); /* EMIT SIGNAL */
235 Playlist::copy_regions (RegionList& newlist) const
237 RegionLock rlock (const_cast<Playlist *> (this));
239 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
240 newlist.push_back (RegionFactory::RegionFactory::create (*i));
245 Playlist::init (bool hide)
247 g_atomic_int_set (&block_notifications, 0);
248 g_atomic_int_set (&ignore_state_changes, 0);
249 pending_modified = false;
250 pending_length = false;
251 first_set_state = true;
258 _edit_mode = Config->get_edit_mode();
260 in_partition = false;
262 _read_data_count = 0;
264 layer_op_counter = 0;
266 _explicit_relayering = false;
268 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
271 Playlist::~Playlist ()
274 RegionLock rl (this);
276 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
277 (*i)->set_playlist (boost::shared_ptr<Playlist>());
281 /* GoingAway must be emitted by derived classes */
285 Playlist::set_name (const string& str)
287 /* in a typical situation, a playlist is being used
288 by one diskstream and also is referenced by the
289 Session. if there are more references than that,
290 then don't change the name.
296 return SessionObject::set_name(str);
300 /***********************************************************************
301 CHANGE NOTIFICATION HANDLING
303 Notifications must be delayed till the region_lock is released. This
304 is necessary because handlers for the signals may need to acquire
305 the lock (e.g. to read from the playlist).
306 ***********************************************************************/
311 delay_notifications ();
312 g_atomic_int_inc (&ignore_state_changes);
318 g_atomic_int_dec_and_test (&ignore_state_changes);
319 release_notifications ();
324 Playlist::delay_notifications ()
326 g_atomic_int_inc (&block_notifications);
327 freeze_length = _get_maximum_extent();
331 Playlist::release_notifications ()
333 if (g_atomic_int_dec_and_test (&block_notifications)) {
334 flush_notifications ();
339 Playlist::notify_modified ()
341 if (holding_state ()) {
342 pending_modified = true;
344 pending_modified = false;
345 Modified(); /* EMIT SIGNAL */
350 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
352 if (holding_state ()) {
353 pending_removes.insert (r);
354 pending_modified = true;
355 pending_length = true;
357 /* this might not be true, but we have to act
358 as though it could be.
360 pending_length = false;
361 LengthChanged (); /* EMIT SIGNAL */
362 pending_modified = false;
363 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
364 Modified (); /* EMIT SIGNAL */
369 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
371 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
373 if (holding_state ()) {
375 pending_range_moves.push_back (move);
379 list< Evoral::RangeMove<nframes_t> > m;
387 Playlist::notify_region_added (boost::shared_ptr<Region> r)
389 /* the length change might not be true, but we have to act
390 as though it could be.
393 if (holding_state()) {
394 pending_adds.insert (r);
395 pending_modified = true;
396 pending_length = true;
398 pending_length = false;
399 LengthChanged (); /* EMIT SIGNAL */
400 pending_modified = false;
401 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
402 Modified (); /* EMIT SIGNAL */
407 Playlist::notify_length_changed ()
409 if (holding_state ()) {
410 pending_length = true;
412 pending_length = false;
413 LengthChanged(); /* EMIT SIGNAL */
414 pending_modified = false;
415 Modified (); /* EMIT SIGNAL */
420 Playlist::flush_notifications ()
422 set<boost::shared_ptr<Region> > dependent_checks_needed;
423 set<boost::shared_ptr<Region> >::iterator s;
432 /* we have no idea what order the regions ended up in pending
433 bounds (it could be based on selection order, for example).
434 so, to preserve layering in the "most recently moved is higher"
435 model, sort them by existing layer, then timestamp them.
438 // RegionSortByLayer cmp;
439 // pending_bounds.sort (cmp);
441 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
442 if (_session.config.get_layer_model() == MoveAddHigher) {
443 timestamp_layer_op (*r);
446 pending_length = true;
447 dependent_checks_needed.insert (*r);
452 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
453 remove_dependents (*s);
454 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
458 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
459 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
460 dependent_checks_needed.insert (*s);
464 if ((freeze_length != _get_maximum_extent()) || pending_length) {
466 LengthChanged(); /* EMIT SIGNAL */
470 if (n || pending_modified) {
474 pending_modified = false;
475 Modified (); /* EMIT SIGNAL */
478 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
479 check_dependents (*s, false);
482 if (!pending_range_moves.empty ()) {
483 RangesMoved (pending_range_moves);
486 pending_adds.clear ();
487 pending_removes.clear ();
488 pending_bounds.clear ();
489 pending_range_moves.clear ();
494 /*************************************************************
496 *************************************************************/
499 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
501 RegionLock rlock (this);
502 times = fabs (times);
504 int itimes = (int) floor (times);
506 nframes_t pos = position;
508 if(times == 1 && auto_partition){
509 partition(pos, (nframes_t) (pos + region->length()), true);
513 add_region_internal (region, pos);
514 pos += region->length();
519 /* note that itimes can be zero if we being asked to just
520 insert a single fraction of the region.
523 for (int i = 0; i < itimes; ++i) {
524 boost::shared_ptr<Region> copy = RegionFactory::create (region);
525 add_region_internal (copy, pos);
526 pos += region->length();
529 nframes_t length = 0;
531 if (floor (times) != times) {
532 length = (nframes_t) floor (region->length() * (times - floor (times)));
534 _session.region_name (name, region->name(), false);
535 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
536 add_region_internal (sub, pos);
539 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
543 Playlist::set_region_ownership ()
545 RegionLock rl (this);
546 RegionList::iterator i;
547 boost::weak_ptr<Playlist> pl (shared_from_this());
549 for (i = regions.begin(); i != regions.end(); ++i) {
550 (*i)->set_playlist (pl);
555 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
557 if (region->data_type() != _type){
561 RegionSortByPosition cmp;
563 nframes_t old_length = 0;
565 if (!holding_state()) {
566 old_length = _get_maximum_extent();
569 if (!first_set_state) {
570 boost::shared_ptr<Playlist> foo (shared_from_this());
571 region->set_playlist (boost::weak_ptr<Playlist>(foo));
574 region->set_position (position, this);
576 timestamp_layer_op (region);
578 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
579 all_regions.insert (region);
581 possibly_splice_unlocked (position, region->length(), region);
583 if (!holding_state () && !in_set_state) {
584 /* layers get assigned from XML state */
588 /* we need to notify the existence of new region before checking dependents. Ick. */
590 notify_region_added (region);
592 if (!holding_state ()) {
594 check_dependents (region, false);
596 if (old_length != _get_maximum_extent()) {
597 notify_length_changed ();
601 region_state_changed_connections.push_back (
602 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
603 boost::weak_ptr<Region> (region)))
610 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
612 RegionLock rlock (this);
614 bool old_sp = _splicing;
617 remove_region_internal (old);
618 add_region_internal (newr, pos);
622 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
626 Playlist::remove_region (boost::shared_ptr<Region> region)
628 RegionLock rlock (this);
629 remove_region_internal (region);
633 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
635 RegionList::iterator i;
636 nframes_t old_length = 0;
638 if (!holding_state()) {
639 old_length = _get_maximum_extent();
644 region->set_playlist (boost::weak_ptr<Playlist>());
647 for (i = regions.begin(); i != regions.end(); ++i) {
650 nframes_t pos = (*i)->position();
651 nframes64_t distance = (*i)->length();
655 possibly_splice_unlocked (pos, -distance);
657 if (!holding_state ()) {
659 remove_dependents (region);
661 if (old_length != _get_maximum_extent()) {
662 notify_length_changed ();
666 notify_region_removed (region);
677 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
679 if (Config->get_use_overlap_equivalency()) {
680 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
681 if ((*i)->overlap_equivalent (other)) {
682 results.push_back ((*i));
686 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
687 if ((*i)->equivalent (other)) {
688 results.push_back ((*i));
695 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
697 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
699 if ((*i) && (*i)->region_list_equivalent (other)) {
700 results.push_back (*i);
706 Playlist::partition (nframes_t start, nframes_t end, bool cut)
710 partition_internal (start, end, cut, thawlist);
712 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
713 (*i)->thaw ("separation");
718 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
720 RegionList new_regions;
723 RegionLock rlock (this);
725 boost::shared_ptr<Region> region;
726 boost::shared_ptr<Region> current;
728 RegionList::iterator tmp;
730 nframes_t pos1, pos2, pos3, pos4;
734 /* need to work from a copy, because otherwise the regions we add during the process
735 get operated on as well.
738 RegionList copy = regions;
740 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
747 if (current->first_frame() >= start && current->last_frame() < end) {
750 remove_region_internal (current);
756 /* coverage will return OverlapStart if the start coincides
757 with the end point. we do not partition such a region,
758 so catch this special case.
761 if (current->first_frame() >= end) {
765 if ((overlap = current->coverage (start, end)) == OverlapNone) {
769 pos1 = current->position();
772 pos4 = current->last_frame();
774 if (overlap == OverlapInternal) {
775 /* split: we need 3 new regions, the front, middle and end.
776 cut: we need 2 regions, the front and end.
781 ---------------*************************------------
784 ---------------*****++++++++++++++++====------------
786 ---------------*****----------------====------------
791 /* "middle" ++++++ */
793 _session.region_name (new_name, current->name(), false);
794 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
795 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
796 add_region_internal (region, start);
797 new_regions.push_back (region);
802 _session.region_name (new_name, current->name(), false);
803 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
804 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
806 add_region_internal (region, end);
807 new_regions.push_back (region);
812 thawlist.push_back (current);
813 current->trim_end (pos2, this);
815 } else if (overlap == OverlapEnd) {
819 ---------------*************************------------
822 ---------------**************+++++++++++------------
824 ---------------**************-----------------------
831 _session.region_name (new_name, current->name(), false);
832 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
833 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
835 add_region_internal (region, start);
836 new_regions.push_back (region);
842 thawlist.push_back (current);
843 current->trim_end (pos2, this);
845 } else if (overlap == OverlapStart) {
847 /* split: we need 2 regions: the front and the end.
848 cut: just trim current to skip the cut area
853 ---------------*************************------------
857 ---------------****+++++++++++++++++++++------------
859 -------------------*********************------------
865 _session.region_name (new_name, current->name(), false);
866 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
867 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
869 add_region_internal (region, pos1);
870 new_regions.push_back (region);
876 thawlist.push_back (current);
877 current->trim_front (pos3, this);
878 } else if (overlap == OverlapExternal) {
880 /* split: no split required.
881 cut: remove the region.
886 ---------------*************************------------
890 ---------------*************************------------
892 ----------------------------------------------------
897 remove_region_internal (current);
900 new_regions.push_back (current);
904 in_partition = false;
907 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
908 check_dependents (*i, false);
912 boost::shared_ptr<Playlist>
913 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
915 boost::shared_ptr<Playlist> ret;
916 boost::shared_ptr<Playlist> pl;
919 if (ranges.empty()) {
920 return boost::shared_ptr<Playlist>();
923 start = ranges.front().start;
925 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
927 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
929 if (i == ranges.begin()) {
933 /* paste the next section into the nascent playlist,
934 offset to reflect the start of the first range we
938 ret->paste (pl, (*i).start - start, 1.0f);
945 boost::shared_ptr<Playlist>
946 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
948 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
949 return cut_copy (pmf, ranges, result_is_hidden);
952 boost::shared_ptr<Playlist>
953 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
955 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
956 return cut_copy (pmf, ranges, result_is_hidden);
959 boost::shared_ptr<Playlist>
960 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
962 boost::shared_ptr<Playlist> the_copy;
966 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
967 string new_name = _name;
971 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
972 return boost::shared_ptr<Playlist>();
975 partition_internal (start, start+cnt-1, true, thawlist);
977 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
978 (*i)->thaw ("playlist cut");
984 boost::shared_ptr<Playlist>
985 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
989 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
990 string new_name = _name;
994 cnt = min (_get_maximum_extent() - start, cnt);
995 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
999 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
1001 times = fabs (times);
1002 nframes_t old_length;
1005 RegionLock rl1 (this);
1006 RegionLock rl2 (other.get());
1008 old_length = _get_maximum_extent();
1010 int itimes = (int) floor (times);
1011 nframes_t pos = position;
1012 nframes_t shift = other->_get_maximum_extent();
1013 layer_t top_layer = regions.size();
1016 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1017 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1019 /* put these new regions on top of all existing ones, but preserve
1020 the ordering they had in the original playlist.
1023 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1024 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1030 /* XXX shall we handle fractional cases at some point? */
1032 if (old_length != _get_maximum_extent()) {
1033 notify_length_changed ();
1044 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1046 times = fabs (times);
1048 RegionLock rl (this);
1049 int itimes = (int) floor (times);
1050 nframes_t pos = position;
1053 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1054 add_region_internal (copy, pos);
1055 pos += region->length();
1058 if (floor (times) != times) {
1059 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1061 _session.region_name (name, region->name(), false);
1062 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1063 add_region_internal (sub, pos);
1068 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1070 RegionLock rlock (this);
1071 RegionList copy (regions);
1074 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1076 if ((*r)->last_frame() < at) {
1081 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1082 /* intersected region */
1083 if (!move_intersected) {
1088 /* do not move regions glued to music time - that
1089 has to be done separately.
1092 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1093 fixup.push_back (*r);
1097 (*r)->set_position ((*r)->position() + distance, this);
1100 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1101 (*r)->recompute_position_from_lock_style ();
1106 Playlist::split (nframes64_t at)
1108 RegionLock rlock (this);
1109 RegionList copy (regions);
1111 /* use a copy since this operation can modify the region list
1114 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1115 _split_region (*r, at);
1120 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1122 RegionLock rl (this);
1123 _split_region (region, playlist_position);
1127 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1129 if (!region->covers (playlist_position)) {
1133 if (region->position() == playlist_position ||
1134 region->last_frame() == playlist_position) {
1138 boost::shared_ptr<Region> left;
1139 boost::shared_ptr<Region> right;
1145 /* split doesn't change anything about length, so don't try to splice */
1147 bool old_sp = _splicing;
1150 before = playlist_position - region->position();
1151 after = region->length() - before;
1153 _session.region_name (before_name, region->name(), false);
1154 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1156 _session.region_name (after_name, region->name(), false);
1157 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1159 add_region_internal (left, region->position());
1160 add_region_internal (right, region->position() + before);
1162 uint64_t orig_layer_op = region->last_layer_op();
1163 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1164 if ((*i)->last_layer_op() > orig_layer_op) {
1165 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1169 left->set_last_layer_op ( orig_layer_op );
1170 right->set_last_layer_op ( orig_layer_op + 1);
1174 finalize_split_region (region, left, right);
1176 remove_region_internal (region);
1182 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1184 if (_splicing || in_set_state) {
1185 /* don't respond to splicing moves or state setting */
1189 if (_edit_mode == Splice) {
1190 splice_locked (at, distance, exclude);
1195 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1197 if (_splicing || in_set_state) {
1198 /* don't respond to splicing moves or state setting */
1202 if (_edit_mode == Splice) {
1203 splice_unlocked (at, distance, exclude);
1208 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1211 RegionLock rl (this);
1212 core_splice (at, distance, exclude);
1217 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1219 core_splice (at, distance, exclude);
1223 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1227 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1229 if (exclude && (*i) == exclude) {
1233 if ((*i)->position() >= at) {
1234 nframes64_t new_pos = (*i)->position() + distance;
1237 } else if (new_pos >= max_frames - (*i)->length()) {
1238 new_pos = max_frames - (*i)->length();
1241 (*i)->set_position (new_pos, this);
1247 notify_length_changed ();
1251 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1253 if (in_set_state || _splicing || _nudging || _shuffling) {
1257 if (what_changed & ARDOUR::PositionChanged) {
1259 /* remove it from the list then add it back in
1260 the right place again.
1263 RegionSortByPosition cmp;
1265 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1267 if (i == regions.end()) {
1268 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1269 _name, region->name())
1275 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1278 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1280 nframes64_t delta = 0;
1282 if (what_changed & ARDOUR::PositionChanged) {
1283 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1286 if (what_changed & ARDOUR::LengthChanged) {
1287 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1291 possibly_splice (region->last_position() + region->last_length(), delta, region);
1294 if (holding_state ()) {
1295 pending_bounds.push_back (region);
1297 if (_session.config.get_layer_model() == MoveAddHigher) {
1298 /* it moved or changed length, so change the timestamp */
1299 timestamp_layer_op (region);
1302 notify_length_changed ();
1304 check_dependents (region, false);
1310 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1312 boost::shared_ptr<Region> region (weak_region.lock());
1319 /* this makes a virtual call to the right kind of playlist ... */
1321 region_changed (what_changed, region);
1325 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1327 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1330 if (in_set_state || in_flush) {
1334 if (what_changed & BoundsChanged) {
1335 region_bounds_changed (what_changed, region);
1336 save = !(_splicing || _nudging);
1339 if ((what_changed & our_interests) &&
1340 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1341 check_dependents (region, false);
1344 if (what_changed & Change (ARDOUR::PositionChanged)) {
1345 notify_region_moved (region);
1348 if (what_changed & our_interests) {
1356 Playlist::drop_regions ()
1358 RegionLock rl (this);
1360 all_regions.clear ();
1364 Playlist::clear (bool with_signals)
1367 RegionLock rl (this);
1370 std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
1371 i != region_state_changed_connections.end ();
1377 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1378 pending_removes.insert (*i);
1385 pending_length = false;
1387 pending_modified = false;
1393 /***********************************************************************
1395 **********************************************************************/
1397 Playlist::RegionList *
1398 Playlist::regions_at (nframes_t frame)
1401 RegionLock rlock (this);
1402 return find_regions_at (frame);
1405 boost::shared_ptr<Region>
1406 Playlist::top_region_at (nframes_t frame)
1409 RegionLock rlock (this);
1410 RegionList *rlist = find_regions_at (frame);
1411 boost::shared_ptr<Region> region;
1413 if (rlist->size()) {
1414 RegionSortByLayer cmp;
1416 region = rlist->back();
1423 Playlist::RegionList*
1424 Playlist::regions_to_read (nframes_t start, nframes_t end)
1426 /* Caller must hold lock */
1428 RegionList covering;
1429 set<nframes_t> to_check;
1430 set<boost::shared_ptr<Region> > unique;
1433 to_check.insert (start);
1434 to_check.insert (end);
1436 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1438 /* find all/any regions that span start+end */
1440 switch ((*i)->coverage (start, end)) {
1444 case OverlapInternal:
1445 covering.push_back (*i);
1449 to_check.insert ((*i)->position());
1450 covering.push_back (*i);
1454 to_check.insert ((*i)->last_frame());
1455 covering.push_back (*i);
1458 case OverlapExternal:
1459 covering.push_back (*i);
1460 to_check.insert ((*i)->position());
1461 to_check.insert ((*i)->last_frame());
1465 /* don't go too far */
1467 if ((*i)->position() > end) {
1472 RegionList* rlist = new RegionList;
1474 /* find all the regions that cover each position .... */
1476 if (covering.size() == 1) {
1478 rlist->push_back (covering.front());
1482 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1486 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1488 if ((*x)->covers (*t)) {
1489 here.push_back (*x);
1493 RegionSortByLayer cmp;
1496 /* ... and get the top/transparent regions at "here" */
1498 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1502 if ((*c)->opaque()) {
1504 /* the other regions at this position are hidden by this one */
1511 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1512 rlist->push_back (*s);
1515 if (rlist->size() > 1) {
1516 /* now sort by time order */
1518 RegionSortByPosition cmp;
1526 Playlist::RegionList *
1527 Playlist::find_regions_at (nframes_t frame)
1529 /* Caller must hold lock */
1531 RegionList *rlist = new RegionList;
1533 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1534 if ((*i)->covers (frame)) {
1535 rlist->push_back (*i);
1542 Playlist::RegionList *
1543 Playlist::regions_touched (nframes_t start, nframes_t end)
1545 RegionLock rlock (this);
1546 RegionList *rlist = new RegionList;
1548 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1549 if ((*i)->coverage (start, end) != OverlapNone) {
1550 rlist->push_back (*i);
1558 Playlist::find_next_transient (nframes64_t from, int dir)
1560 RegionLock rlock (this);
1561 AnalysisFeatureList points;
1562 AnalysisFeatureList these_points;
1564 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1566 if ((*i)->last_frame() < from) {
1570 if ((*i)->first_frame() > from) {
1575 (*i)->get_transients (these_points);
1577 /* add first frame, just, err, because */
1579 these_points.push_back ((*i)->first_frame());
1581 points.insert (points.end(), these_points.begin(), these_points.end());
1582 these_points.clear ();
1585 if (points.empty()) {
1589 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1590 bool reached = false;
1593 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1598 if (reached && (*x) > from) {
1603 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1608 if (reached && (*x) < from) {
1617 boost::shared_ptr<Region>
1618 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1620 RegionLock rlock (this);
1621 boost::shared_ptr<Region> ret;
1622 nframes_t closest = max_frames;
1624 bool end_iter = false;
1626 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1631 boost::shared_ptr<Region> r = (*i);
1636 pos = r->first_frame ();
1639 pos = r->last_frame ();
1642 pos = r->sync_position ();
1643 // r->adjust_to_sync (r->first_frame());
1648 case 1: /* forwards */
1651 if ((distance = pos - frame) < closest) {
1660 default: /* backwards */
1663 if ((distance = frame - pos) < closest) {
1680 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1682 RegionLock rlock (this);
1684 nframes64_t closest = max_frames;
1685 nframes64_t ret = -1;
1689 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1691 boost::shared_ptr<Region> r = (*i);
1692 nframes64_t distance;
1694 if (r->first_frame() > frame) {
1696 distance = r->first_frame() - frame;
1698 if (distance < closest) {
1699 ret = r->first_frame();
1704 if (r->last_frame () > frame) {
1706 distance = r->last_frame () - frame;
1708 if (distance < closest) {
1709 ret = r->last_frame ();
1717 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1719 boost::shared_ptr<Region> r = (*i);
1720 nframes64_t distance;
1722 if (r->last_frame() < frame) {
1724 distance = frame - r->last_frame();
1726 if (distance < closest) {
1727 ret = r->last_frame();
1732 if (r->first_frame() < frame) {
1734 distance = frame - r->first_frame();
1736 if (distance < closest) {
1737 ret = r->first_frame();
1747 /***********************************************************************/
1753 Playlist::mark_session_dirty ()
1755 if (!in_set_state && !holding_state ()) {
1756 _session.set_dirty();
1761 Playlist::set_state (const XMLNode& node)
1765 XMLNodeConstIterator niter;
1766 XMLPropertyList plist;
1767 XMLPropertyConstIterator piter;
1769 boost::shared_ptr<Region> region;
1774 if (node.name() != "Playlist") {
1781 plist = node.properties();
1783 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1787 if (prop->name() == X_("name")) {
1788 _name = prop->value();
1789 } else if (prop->name() == X_("orig_diskstream_id")) {
1790 _orig_diskstream_id = prop->value ();
1791 } else if (prop->name() == X_("frozen")) {
1792 _frozen = (prop->value() == X_("yes"));
1798 nlist = node.children();
1800 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1804 if (child->name() == "Region") {
1806 if ((prop = child->property ("id")) == 0) {
1807 error << _("region state node has no ID, ignored") << endmsg;
1811 ID id = prop->value ();
1813 if ((region = region_by_id (id))) {
1815 Change what_changed = Change (0);
1817 if (region->set_live_state (*child, what_changed, true)) {
1818 error << _("Playlist: cannot reset region state from XML") << endmsg;
1822 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1823 error << _("Playlist: cannot create region from XML") << endmsg;
1827 add_region (region, region->position(), 1.0);
1829 // So that layer_op ordering doesn't get screwed up
1830 region->set_last_layer_op( region->layer());
1839 /* update dependents, which was not done during add_region_internal
1840 due to in_set_state being true
1843 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1844 check_dependents (*r, false);
1848 first_set_state = false;
1853 Playlist::get_state()
1855 return state (true);
1859 Playlist::get_template()
1861 return state (false);
1864 /** @param full_state true to include regions in the returned state, otherwise false.
1867 Playlist::state (bool full_state)
1869 XMLNode *node = new XMLNode (X_("Playlist"));
1872 node->add_property (X_("name"), _name);
1873 node->add_property (X_("type"), _type.to_string());
1875 _orig_diskstream_id.print (buf, sizeof (buf));
1876 node->add_property (X_("orig_diskstream_id"), buf);
1877 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1880 RegionLock rlock (this, false);
1881 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1882 node->add_child_nocopy ((*i)->get_state());
1887 node->add_child_copy (*_extra_xml);
1894 Playlist::empty() const
1896 RegionLock rlock (const_cast<Playlist *>(this), false);
1897 return regions.empty();
1901 Playlist::n_regions() const
1903 RegionLock rlock (const_cast<Playlist *>(this), false);
1904 return regions.size();
1908 Playlist::get_maximum_extent () const
1910 RegionLock rlock (const_cast<Playlist *>(this), false);
1911 return _get_maximum_extent ();
1915 Playlist::_get_maximum_extent () const
1917 RegionList::const_iterator i;
1918 nframes_t max_extent = 0;
1921 for (i = regions.begin(); i != regions.end(); ++i) {
1922 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1931 Playlist::bump_name (string name, Session &session)
1933 string newname = name;
1936 newname = bump_name_once (newname);
1937 } while (session.playlist_by_name (newname)!=NULL);
1944 Playlist::top_layer() const
1946 RegionLock rlock (const_cast<Playlist *> (this));
1949 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1950 top = max (top, (*i)->layer());
1956 Playlist::set_edit_mode (EditMode mode)
1961 /********************
1963 ********************/
1966 Playlist::relayer ()
1968 /* don't send multiple Modified notifications
1969 when multiple regions are relayered.
1974 /* Build up a new list of regions on each layer, stored in a set of lists
1975 each of which represent some period of time on some layer. The idea
1976 is to avoid having to search the entire region list to establish whether
1977 each region overlaps another */
1979 /* how many pieces to divide this playlist's time up into */
1980 int const divisions = 512;
1982 /* find the start and end positions of the regions on this playlist */
1983 nframes_t start = UINT_MAX;
1985 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1986 start = min (start, (*i)->position());
1987 end = max (end, (*i)->position() + (*i)->length());
1990 /* hence the size of each time division */
1991 double const division_size = (end - start) / divisions;
1993 vector<vector<RegionList> > layers;
1994 layers.push_back (vector<RegionList> (divisions));
1996 /* we want to go through regions from desired lowest to desired highest layer,
1997 which depends on the layer model
2000 RegionList copy = regions;
2002 /* sort according to the model and the layering mode that we're in */
2004 if (_explicit_relayering) {
2006 copy.sort (RegionSortByLayerWithPending ());
2008 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2010 copy.sort (RegionSortByLastLayerOp ());
2014 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2016 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2017 (*i)->set_pending_explicit_relayer (false);
2019 /* find the time divisions that this region covers */
2020 int const start_division = floor ( ((*i)->position() - start) / division_size);
2021 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2022 if (end_division == divisions) {
2026 /* find the lowest layer that this region can go on */
2027 size_t j = layers.size();
2029 /* try layer j - 1; it can go on if it overlaps no other region
2030 that is already on that layer
2033 bool overlap = false;
2034 for (int k = start_division; k <= end_division; ++k) {
2035 RegionList::iterator l = layers[j-1][k].begin ();
2036 while (l != layers[j-1][k].end()) {
2037 if ((*l)->overlap_equivalent (*i)) {
2050 /* overlap, so we must use layer j */
2057 if (j == layers.size()) {
2058 /* we need a new layer for this region */
2059 layers.push_back (vector<RegionList> (divisions));
2062 /* put a reference to this region in each of the divisions that it exists in */
2063 for (int k = start_division; k <= end_division; ++k) {
2064 layers[j][k].push_back (*i);
2067 (*i)->set_layer (j);
2070 /* sending Modified means that various kinds of layering
2071 models operate correctly at the GUI
2072 level. slightly inefficient, but only slightly.
2074 We force a Modified signal here in case no layers actually
2083 /* XXX these layer functions are all deprecated */
2086 Playlist::raise_region (boost::shared_ptr<Region> region)
2088 uint32_t rsz = regions.size();
2089 layer_t target = region->layer() + 1U;
2091 if (target >= rsz) {
2092 /* its already at the effective top */
2096 move_region_to_layer (target, region, 1);
2100 Playlist::lower_region (boost::shared_ptr<Region> region)
2102 if (region->layer() == 0) {
2103 /* its already at the bottom */
2107 layer_t target = region->layer() - 1U;
2109 move_region_to_layer (target, region, -1);
2113 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2115 /* does nothing useful if layering mode is later=higher */
2116 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2117 (_session.config.get_layer_model() == AddHigher)) {
2118 timestamp_layer_op (region);
2124 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2126 /* does nothing useful if layering mode is later=higher */
2127 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2128 (_session.config.get_layer_model() == AddHigher)) {
2129 region->set_last_layer_op (0);
2135 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2137 RegionList::iterator i;
2138 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2139 list<LayerInfo> layerinfo;
2143 RegionLock rlock (const_cast<Playlist *> (this));
2145 for (i = regions.begin(); i != regions.end(); ++i) {
2153 /* region is moving up, move all regions on intermediate layers
2157 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2158 dest = (*i)->layer() - 1;
2165 /* region is moving down, move all regions on intermediate layers
2169 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2170 dest = (*i)->layer() + 1;
2180 newpair.second = dest;
2182 layerinfo.push_back (newpair);
2186 /* now reset the layers without holding the region lock */
2188 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2189 x->first->set_layer (x->second);
2192 region->set_layer (target_layer);
2195 /* now check all dependents */
2197 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2198 check_dependents (x->first, false);
2201 check_dependents (region, false);
2208 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2210 RegionList::iterator i;
2217 RegionLock rlock (const_cast<Playlist *> (this));
2219 for (i = regions.begin(); i != regions.end(); ++i) {
2221 if ((*i)->position() >= start) {
2225 if ((*i)->last_frame() > max_frames - distance) {
2226 new_pos = max_frames - (*i)->length();
2228 new_pos = (*i)->position() + distance;
2233 if ((*i)->position() > distance) {
2234 new_pos = (*i)->position() - distance;
2240 (*i)->set_position (new_pos, this);
2248 notify_length_changed ();
2253 boost::shared_ptr<Region>
2254 Playlist::find_region (const ID& id) const
2256 RegionLock rlock (const_cast<Playlist*> (this));
2258 /* searches all regions currently in use by the playlist */
2260 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2261 if ((*i)->id() == id) {
2266 return boost::shared_ptr<Region> ();
2269 boost::shared_ptr<Region>
2270 Playlist::region_by_id (ID id)
2272 /* searches all regions ever added to this playlist */
2274 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2275 if ((*i)->id() == id) {
2279 return boost::shared_ptr<Region> ();
2283 Playlist::dump () const
2285 boost::shared_ptr<Region> r;
2287 cerr << "Playlist \"" << _name << "\" " << endl
2288 << regions.size() << " regions "
2291 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2293 cerr << " " << r->name() << " ["
2294 << r->start() << "+" << r->length()
2304 Playlist::set_frozen (bool yn)
2310 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2312 // struct timeval tv;
2313 // gettimeofday (&tv, 0);
2314 region->set_last_layer_op (++layer_op_counter);
2319 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2324 if (region->locked()) {
2331 RegionLock rlock (const_cast<Playlist*> (this));
2336 RegionList::iterator next;
2338 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2339 if ((*i) == region) {
2343 if (next != regions.end()) {
2345 if ((*next)->locked()) {
2349 if ((*next)->position() != region->last_frame() + 1) {
2350 /* they didn't used to touch, so after shuffle,
2351 just have them swap positions.
2353 new_pos = (*next)->position();
2355 /* they used to touch, so after shuffle,
2356 make sure they still do. put the earlier
2357 region where the later one will end after
2360 new_pos = region->position() + (*next)->length();
2363 (*next)->set_position (region->position(), this);
2364 region->set_position (new_pos, this);
2366 /* avoid a full sort */
2368 regions.erase (i); // removes the region from the list */
2370 regions.insert (next, region); // adds it back after next
2379 RegionList::iterator prev = regions.end();
2381 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2382 if ((*i) == region) {
2384 if (prev != regions.end()) {
2386 if ((*prev)->locked()) {
2390 if (region->position() != (*prev)->last_frame() + 1) {
2391 /* they didn't used to touch, so after shuffle,
2392 just have them swap positions.
2394 new_pos = region->position();
2396 /* they used to touch, so after shuffle,
2397 make sure they still do. put the earlier
2398 one where the later one will end after
2400 new_pos = (*prev)->position() + region->length();
2403 region->set_position ((*prev)->position(), this);
2404 (*prev)->set_position (new_pos, this);
2406 /* avoid a full sort */
2408 regions.erase (i); // remove region
2409 regions.insert (prev, region); // insert region before prev
2425 check_dependents (region, false);
2433 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2435 RegionLock rlock (const_cast<Playlist*> (this));
2437 if (regions.size() > 1) {
2445 Playlist::update_after_tempo_map_change ()
2447 RegionLock rlock (const_cast<Playlist*> (this));
2448 RegionList copy (regions);
2452 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2453 (*i)->update_position_after_tempo_map_change ();
2460 Playlist::foreach_region (sigc::slot<void, boost::shared_ptr<Region> > s)
2462 RegionLock rl (this, false);
2463 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {