2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "pbd/failed_constructor.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/xml++.h"
32 #include "pbd/stacktrace.h"
34 #include "ardour/debug.h"
35 #include "ardour/playlist.h"
36 #include "ardour/session.h"
37 #include "ardour/region.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/playlist_factory.h"
40 #include "ardour/transient_detector.h"
41 #include "ardour/session_playlists.h"
46 using namespace ARDOUR;
49 struct ShowMeTheList {
50 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
52 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
54 boost::shared_ptr<Playlist> playlist;
58 struct RegionSortByLayer {
59 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
60 return a->layer() < b->layer();
64 struct RegionSortByLayerWithPending {
65 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
67 double p = a->layer ();
68 if (a->pending_explicit_relayer()) {
72 double q = b->layer ();
73 if (b->pending_explicit_relayer()) {
81 struct RegionSortByPosition {
82 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
83 return a->position() < b->position();
87 struct RegionSortByLastLayerOp {
88 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
89 return a->last_layer_op() < b->last_layer_op();
94 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
95 : SessionObject(sess, nom)
99 first_set_state = false;
104 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
105 : SessionObject(sess, "unnamed playlist")
108 const XMLProperty* prop = node.property("type");
109 assert(!prop || DataType(prop->value()) == _type);
112 _name = "unnamed"; /* reset by set_state */
114 /* set state called by derived class */
117 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
118 : SessionObject(other->_session, namestr)
119 , _type(other->_type)
120 , _orig_diskstream_id(other->_orig_diskstream_id)
125 other->copy_regions (tmp);
129 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
130 add_region_internal( (*x), (*x)->position());
135 _splicing = other->_splicing;
136 _nudging = other->_nudging;
137 _edit_mode = other->_edit_mode;
140 first_set_state = false;
142 in_partition = false;
144 _read_data_count = 0;
145 _frozen = other->_frozen;
147 layer_op_counter = other->layer_op_counter;
148 freeze_length = other->freeze_length;
151 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
152 : SessionObject(other->_session, str)
153 , _type(other->_type)
154 , _orig_diskstream_id(other->_orig_diskstream_id)
156 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
158 nframes_t end = start + cnt - 1;
164 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
166 boost::shared_ptr<Region> region;
167 boost::shared_ptr<Region> new_region;
168 nframes_t offset = 0;
169 nframes_t position = 0;
176 overlap = region->coverage (start, end);
182 case OverlapInternal:
183 offset = start - region->position();
190 position = region->position() - start;
191 len = end - region->position();
195 offset = start - region->position();
197 len = region->length() - offset;
200 case OverlapExternal:
202 position = region->position() - start;
203 len = region->length();
207 _session.region_name (new_name, region->name(), false);
209 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
211 add_region_internal (new_region, position);
215 first_set_state = false;
217 /* this constructor does NOT notify others (session) */
224 InUse (true); /* EMIT SIGNAL */
235 InUse (false); /* EMIT SIGNAL */
240 Playlist::copy_regions (RegionList& newlist) const
242 RegionLock rlock (const_cast<Playlist *> (this));
244 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
245 newlist.push_back (RegionFactory::RegionFactory::create (*i));
250 Playlist::init (bool hide)
252 g_atomic_int_set (&block_notifications, 0);
253 g_atomic_int_set (&ignore_state_changes, 0);
254 pending_contents_change = false;
255 pending_length = false;
256 pending_layering = false;
257 first_set_state = true;
264 _edit_mode = Config->get_edit_mode();
266 in_partition = false;
268 _read_data_count = 0;
270 layer_op_counter = 0;
272 _explicit_relayering = false;
274 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
277 Playlist::~Playlist ()
279 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
282 RegionLock rl (this);
284 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
285 (*i)->set_playlist (boost::shared_ptr<Playlist>());
289 /* GoingAway must be emitted by derived classes */
293 Playlist::set_name (const string& str)
295 /* in a typical situation, a playlist is being used
296 by one diskstream and also is referenced by the
297 Session. if there are more references than that,
298 then don't change the name.
304 return SessionObject::set_name(str);
308 /***********************************************************************
309 CHANGE NOTIFICATION HANDLING
311 Notifications must be delayed till the region_lock is released. This
312 is necessary because handlers for the signals may need to acquire
313 the lock (e.g. to read from the playlist).
314 ***********************************************************************/
319 delay_notifications ();
320 g_atomic_int_inc (&ignore_state_changes);
326 g_atomic_int_dec_and_test (&ignore_state_changes);
327 release_notifications ();
332 Playlist::delay_notifications ()
334 g_atomic_int_inc (&block_notifications);
335 freeze_length = _get_maximum_extent();
339 Playlist::release_notifications ()
341 if (g_atomic_int_dec_and_test (&block_notifications)) {
342 flush_notifications ();
347 Playlist::notify_contents_changed ()
349 if (holding_state ()) {
350 pending_contents_change = true;
352 pending_contents_change = false;
353 cerr << _name << "send contents change @ " << get_microseconds() << endl;
354 ContentsChanged(); /* EMIT SIGNAL */
355 cerr << _name << "done with cc @ " << get_microseconds() << endl;
360 Playlist::notify_layering_changed ()
362 if (holding_state ()) {
363 pending_layering = true;
365 pending_layering = false;
366 cerr << _name << "send layering @ " << get_microseconds() << endl;
367 LayeringChanged(); /* EMIT SIGNAL */
368 cerr << _name << "done with layering @ " << get_microseconds() << endl;
373 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
375 if (holding_state ()) {
376 pending_removes.insert (r);
377 pending_contents_change = true;
378 pending_length = true;
380 /* this might not be true, but we have to act
381 as though it could be.
383 pending_length = false;
384 LengthChanged (); /* EMIT SIGNAL */
385 pending_contents_change = false;
386 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
387 ContentsChanged (); /* EMIT SIGNAL */
392 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
394 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
396 if (holding_state ()) {
398 pending_range_moves.push_back (move);
402 list< Evoral::RangeMove<nframes_t> > m;
410 Playlist::notify_region_added (boost::shared_ptr<Region> r)
412 /* the length change might not be true, but we have to act
413 as though it could be.
416 if (holding_state()) {
417 pending_adds.insert (r);
418 pending_contents_change = true;
419 pending_length = true;
421 pending_length = false;
422 LengthChanged (); /* EMIT SIGNAL */
423 pending_contents_change = false;
424 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
425 cerr << _name << "send3 contents changed @ " << get_microseconds() << endl;
426 ContentsChanged (); /* EMIT SIGNAL */
427 cerr << _name << "done contents changed @ " << get_microseconds() << endl;
432 Playlist::notify_length_changed ()
434 if (holding_state ()) {
435 pending_length = true;
437 pending_length = false;
438 LengthChanged(); /* EMIT SIGNAL */
439 pending_contents_change = false;
440 cerr << _name << "send4 contents change @ " << get_microseconds() << endl;
441 ContentsChanged (); /* EMIT SIGNAL */
442 cerr << _name << "done contents change @ " << get_microseconds() << endl;
447 Playlist::flush_notifications ()
449 set<boost::shared_ptr<Region> > dependent_checks_needed;
450 set<boost::shared_ptr<Region> >::iterator s;
451 uint32_t regions_changed = false;
452 bool check_length = false;
453 nframes64_t old_length = 0;
461 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
462 regions_changed = true;
463 if (!pending_length) {
464 old_length = _get_maximum_extent ();
469 /* we have no idea what order the regions ended up in pending
470 bounds (it could be based on selection order, for example).
471 so, to preserve layering in the "most recently moved is higher"
472 model, sort them by existing layer, then timestamp them.
475 // RegionSortByLayer cmp;
476 // pending_bounds.sort (cmp);
478 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
479 if (_session.config.get_layer_model() == MoveAddHigher) {
480 timestamp_layer_op (*r);
482 dependent_checks_needed.insert (*r);
485 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
486 remove_dependents (*s);
487 cerr << _name << " sends RegionRemoved\n";
488 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
491 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
492 cerr << _name << " sends RegionAdded\n";
493 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
494 dependent_checks_needed.insert (*s);
498 if (old_length != _get_maximum_extent()) {
499 pending_length = true;
500 cerr << _name << " length has changed\n";
504 if (pending_length || (freeze_length != _get_maximum_extent())) {
505 pending_length = false;
506 cerr << _name << " sends LengthChanged\n";
507 LengthChanged(); /* EMIT SIGNAL */
510 if (regions_changed || pending_contents_change) {
514 pending_contents_change = false;
515 cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
516 ContentsChanged (); /* EMIT SIGNAL */
517 cerr << _name << "done contents change @ " << get_microseconds() << endl;
520 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
521 check_dependents (*s, false);
524 if (!pending_range_moves.empty ()) {
525 cerr << _name << " sends RangesMoved\n";
526 RangesMoved (pending_range_moves);
535 Playlist::clear_pending ()
537 pending_adds.clear ();
538 pending_removes.clear ();
539 pending_bounds.clear ();
540 pending_range_moves.clear ();
541 pending_contents_change = false;
542 pending_length = false;
545 /*************************************************************
547 *************************************************************/
550 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
552 RegionLock rlock (this);
553 times = fabs (times);
555 int itimes = (int) floor (times);
557 nframes_t pos = position;
559 if (times == 1 && auto_partition){
560 partition(pos, (nframes_t) (pos + region->length()), true);
564 add_region_internal (region, pos);
565 pos += region->length();
570 /* note that itimes can be zero if we being asked to just
571 insert a single fraction of the region.
574 for (int i = 0; i < itimes; ++i) {
575 boost::shared_ptr<Region> copy = RegionFactory::create (region);
576 add_region_internal (copy, pos);
577 pos += region->length();
580 nframes_t length = 0;
582 if (floor (times) != times) {
583 length = (nframes_t) floor (region->length() * (times - floor (times)));
585 _session.region_name (name, region->name(), false);
586 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
587 add_region_internal (sub, pos);
590 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
594 Playlist::set_region_ownership ()
596 RegionLock rl (this);
597 RegionList::iterator i;
598 boost::weak_ptr<Playlist> pl (shared_from_this());
600 for (i = regions.begin(); i != regions.end(); ++i) {
601 (*i)->set_playlist (pl);
606 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
608 if (region->data_type() != _type){
612 RegionSortByPosition cmp;
614 nframes_t old_length = 0;
616 if (!holding_state()) {
617 old_length = _get_maximum_extent();
620 if (!first_set_state) {
621 boost::shared_ptr<Playlist> foo (shared_from_this());
622 region->set_playlist (boost::weak_ptr<Playlist>(foo));
625 region->set_position (position, this);
627 timestamp_layer_op (region);
629 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
630 all_regions.insert (region);
632 possibly_splice_unlocked (position, region->length(), region);
634 if (!holding_state () && !in_set_state) {
635 /* layers get assigned from XML state */
639 /* we need to notify the existence of new region before checking dependents. Ick. */
641 notify_region_added (region);
643 if (!holding_state ()) {
645 check_dependents (region, false);
647 if (old_length != _get_maximum_extent()) {
648 notify_length_changed ();
652 region->StateChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
658 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
660 RegionLock rlock (this);
662 bool old_sp = _splicing;
665 remove_region_internal (old);
666 add_region_internal (newr, pos);
670 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
674 Playlist::remove_region (boost::shared_ptr<Region> region)
676 RegionLock rlock (this);
677 remove_region_internal (region);
681 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
683 RegionList::iterator i;
684 nframes_t old_length = 0;
687 if (!holding_state()) {
688 old_length = _get_maximum_extent();
693 region->set_playlist (boost::weak_ptr<Playlist>());
696 /* XXX should probably freeze here .... */
698 for (i = regions.begin(); i != regions.end(); ++i) {
701 nframes_t pos = (*i)->position();
702 nframes64_t distance = (*i)->length();
706 possibly_splice_unlocked (pos, -distance);
708 if (!holding_state ()) {
710 remove_dependents (region);
712 if (old_length != _get_maximum_extent()) {
713 notify_length_changed ();
717 notify_region_removed (region);
723 /* XXX and thaw ... */
729 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
731 if (Config->get_use_overlap_equivalency()) {
732 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
733 if ((*i)->overlap_equivalent (other)) {
734 results.push_back ((*i));
738 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
739 if ((*i)->equivalent (other)) {
740 results.push_back ((*i));
747 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
749 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
751 if ((*i) && (*i)->region_list_equivalent (other)) {
752 results.push_back (*i);
758 Playlist::partition (nframes_t start, nframes_t end, bool cut)
762 partition_internal (start, end, cut, thawlist);
764 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
770 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
772 RegionList new_regions;
775 RegionLock rlock (this);
777 boost::shared_ptr<Region> region;
778 boost::shared_ptr<Region> current;
780 RegionList::iterator tmp;
782 nframes_t pos1, pos2, pos3, pos4;
786 /* need to work from a copy, because otherwise the regions we add during the process
787 get operated on as well.
790 RegionList copy = regions;
792 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
799 if (current->first_frame() >= start && current->last_frame() < end) {
802 remove_region_internal (current);
808 /* coverage will return OverlapStart if the start coincides
809 with the end point. we do not partition such a region,
810 so catch this special case.
813 if (current->first_frame() >= end) {
817 if ((overlap = current->coverage (start, end)) == OverlapNone) {
821 pos1 = current->position();
824 pos4 = current->last_frame();
826 if (overlap == OverlapInternal) {
827 /* split: we need 3 new regions, the front, middle and end.
828 cut: we need 2 regions, the front and end.
833 ---------------*************************------------
836 ---------------*****++++++++++++++++====------------
838 ---------------*****----------------====------------
843 /* "middle" ++++++ */
845 _session.region_name (new_name, current->name(), false);
846 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
847 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
848 add_region_internal (region, start);
849 new_regions.push_back (region);
854 _session.region_name (new_name, current->name(), false);
855 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
856 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
858 add_region_internal (region, end);
859 new_regions.push_back (region);
864 thawlist.push_back (current);
865 current->trim_end (pos2, this);
867 } else if (overlap == OverlapEnd) {
871 ---------------*************************------------
874 ---------------**************+++++++++++------------
876 ---------------**************-----------------------
883 _session.region_name (new_name, current->name(), false);
884 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
885 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
887 add_region_internal (region, start);
888 new_regions.push_back (region);
894 thawlist.push_back (current);
895 current->trim_end (pos2, this);
897 } else if (overlap == OverlapStart) {
899 /* split: we need 2 regions: the front and the end.
900 cut: just trim current to skip the cut area
905 ---------------*************************------------
909 ---------------****+++++++++++++++++++++------------
911 -------------------*********************------------
917 _session.region_name (new_name, current->name(), false);
918 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
919 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
921 add_region_internal (region, pos1);
922 new_regions.push_back (region);
928 thawlist.push_back (current);
929 current->trim_front (pos3, this);
930 } else if (overlap == OverlapExternal) {
932 /* split: no split required.
933 cut: remove the region.
938 ---------------*************************------------
942 ---------------*************************------------
944 ----------------------------------------------------
949 remove_region_internal (current);
952 new_regions.push_back (current);
956 in_partition = false;
959 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
960 check_dependents (*i, false);
964 boost::shared_ptr<Playlist>
965 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
967 boost::shared_ptr<Playlist> ret;
968 boost::shared_ptr<Playlist> pl;
971 if (ranges.empty()) {
972 return boost::shared_ptr<Playlist>();
975 start = ranges.front().start;
977 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
979 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
981 if (i == ranges.begin()) {
985 /* paste the next section into the nascent playlist,
986 offset to reflect the start of the first range we
990 ret->paste (pl, (*i).start - start, 1.0f);
997 boost::shared_ptr<Playlist>
998 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1000 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
1001 return cut_copy (pmf, ranges, result_is_hidden);
1004 boost::shared_ptr<Playlist>
1005 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1007 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
1008 return cut_copy (pmf, ranges, result_is_hidden);
1011 boost::shared_ptr<Playlist>
1012 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
1014 boost::shared_ptr<Playlist> the_copy;
1015 RegionList thawlist;
1018 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1019 string new_name = _name;
1023 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1024 return boost::shared_ptr<Playlist>();
1027 partition_internal (start, start+cnt-1, true, thawlist);
1029 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1036 boost::shared_ptr<Playlist>
1037 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
1041 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1042 string new_name = _name;
1046 cnt = min (_get_maximum_extent() - start, cnt);
1047 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1051 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
1053 times = fabs (times);
1054 nframes_t old_length;
1057 RegionLock rl1 (this);
1058 RegionLock rl2 (other.get());
1060 old_length = _get_maximum_extent();
1062 int itimes = (int) floor (times);
1063 nframes_t pos = position;
1064 nframes_t shift = other->_get_maximum_extent();
1065 layer_t top_layer = regions.size();
1068 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1069 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1071 /* put these new regions on top of all existing ones, but preserve
1072 the ordering they had in the original playlist.
1075 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1076 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1082 /* XXX shall we handle fractional cases at some point? */
1084 if (old_length != _get_maximum_extent()) {
1085 notify_length_changed ();
1096 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1098 times = fabs (times);
1100 RegionLock rl (this);
1101 int itimes = (int) floor (times);
1102 nframes_t pos = position;
1105 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1106 add_region_internal (copy, pos);
1107 pos += region->length();
1110 if (floor (times) != times) {
1111 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1113 _session.region_name (name, region->name(), false);
1114 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1115 add_region_internal (sub, pos);
1120 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1122 RegionLock rlock (this);
1123 RegionList copy (regions);
1126 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1128 if ((*r)->last_frame() < at) {
1133 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1134 /* intersected region */
1135 if (!move_intersected) {
1140 /* do not move regions glued to music time - that
1141 has to be done separately.
1144 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1145 fixup.push_back (*r);
1149 (*r)->set_position ((*r)->position() + distance, this);
1152 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1153 (*r)->recompute_position_from_lock_style ();
1158 Playlist::split (nframes64_t at)
1160 RegionLock rlock (this);
1161 RegionList copy (regions);
1163 /* use a copy since this operation can modify the region list
1166 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1167 _split_region (*r, at);
1172 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1174 RegionLock rl (this);
1175 _split_region (region, playlist_position);
1179 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1181 if (!region->covers (playlist_position)) {
1185 if (region->position() == playlist_position ||
1186 region->last_frame() == playlist_position) {
1190 boost::shared_ptr<Region> left;
1191 boost::shared_ptr<Region> right;
1197 /* split doesn't change anything about length, so don't try to splice */
1199 bool old_sp = _splicing;
1202 before = playlist_position - region->position();
1203 after = region->length() - before;
1205 _session.region_name (before_name, region->name(), false);
1206 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1208 _session.region_name (after_name, region->name(), false);
1209 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1211 add_region_internal (left, region->position());
1212 add_region_internal (right, region->position() + before);
1214 uint64_t orig_layer_op = region->last_layer_op();
1215 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1216 if ((*i)->last_layer_op() > orig_layer_op) {
1217 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1221 left->set_last_layer_op ( orig_layer_op );
1222 right->set_last_layer_op ( orig_layer_op + 1);
1226 finalize_split_region (region, left, right);
1228 remove_region_internal (region);
1234 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1236 if (_splicing || in_set_state) {
1237 /* don't respond to splicing moves or state setting */
1241 if (_edit_mode == Splice) {
1242 splice_locked (at, distance, exclude);
1247 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1249 if (_splicing || in_set_state) {
1250 /* don't respond to splicing moves or state setting */
1254 if (_edit_mode == Splice) {
1255 splice_unlocked (at, distance, exclude);
1260 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1263 RegionLock rl (this);
1264 core_splice (at, distance, exclude);
1269 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1271 core_splice (at, distance, exclude);
1275 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1279 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1281 if (exclude && (*i) == exclude) {
1285 if ((*i)->position() >= at) {
1286 nframes64_t new_pos = (*i)->position() + distance;
1289 } else if (new_pos >= max_frames - (*i)->length()) {
1290 new_pos = max_frames - (*i)->length();
1293 (*i)->set_position (new_pos, this);
1299 notify_length_changed ();
1303 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1305 if (in_set_state || _splicing || _nudging || _shuffling) {
1309 if (what_changed & ARDOUR::PositionChanged) {
1311 /* remove it from the list then add it back in
1312 the right place again.
1315 RegionSortByPosition cmp;
1317 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1319 if (i == regions.end()) {
1320 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1321 _name, region->name())
1327 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1330 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1332 nframes64_t delta = 0;
1334 if (what_changed & ARDOUR::PositionChanged) {
1335 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1338 if (what_changed & ARDOUR::LengthChanged) {
1339 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1343 possibly_splice (region->last_position() + region->last_length(), delta, region);
1346 if (holding_state ()) {
1347 pending_bounds.push_back (region);
1349 if (_session.config.get_layer_model() == MoveAddHigher) {
1350 /* it moved or changed length, so change the timestamp */
1351 timestamp_layer_op (region);
1354 notify_length_changed ();
1356 check_dependents (region, false);
1362 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1364 boost::shared_ptr<Region> region (weak_region.lock());
1370 /* this makes a virtual call to the right kind of playlist ... */
1372 region_changed (what_changed, region);
1376 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1378 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1381 if (in_set_state || in_flush) {
1385 if (what_changed & BoundsChanged) {
1386 region_bounds_changed (what_changed, region);
1387 save = !(_splicing || _nudging);
1390 if ((what_changed & our_interests) &&
1391 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1392 check_dependents (region, false);
1395 if (what_changed & Change (ARDOUR::PositionChanged)) {
1396 notify_region_moved (region);
1400 /* don't notify about layer changes, since we are the only object that can initiate
1401 them, and we notify in ::relayer()
1404 if (what_changed & our_interests) {
1412 Playlist::drop_regions ()
1414 RegionLock rl (this);
1416 all_regions.clear ();
1420 Playlist::clear (bool with_signals)
1423 RegionLock rl (this);
1425 region_state_changed_connections.drop_connections ();
1427 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1428 pending_removes.insert (*i);
1435 pending_length = false;
1437 pending_contents_change = false;
1438 cerr << _name << "send2 contents change @ " << get_microseconds() << endl;
1440 cerr << _name << "done with contents changed @ " << get_microseconds() << endl;
1445 /***********************************************************************
1447 **********************************************************************/
1449 Playlist::RegionList *
1450 Playlist::regions_at (nframes_t frame)
1453 RegionLock rlock (this);
1454 return find_regions_at (frame);
1457 boost::shared_ptr<Region>
1458 Playlist::top_region_at (nframes_t frame)
1461 RegionLock rlock (this);
1462 RegionList *rlist = find_regions_at (frame);
1463 boost::shared_ptr<Region> region;
1465 if (rlist->size()) {
1466 RegionSortByLayer cmp;
1468 region = rlist->back();
1475 boost::shared_ptr<Region>
1476 Playlist::top_unmuted_region_at (nframes_t frame)
1479 RegionLock rlock (this);
1480 RegionList *rlist = find_regions_at (frame);
1482 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1484 RegionList::iterator tmp = i;
1487 if ((*i)->muted()) {
1494 boost::shared_ptr<Region> region;
1496 if (rlist->size()) {
1497 RegionSortByLayer cmp;
1499 region = rlist->back();
1506 Playlist::RegionList*
1507 Playlist::regions_to_read (nframes_t start, nframes_t end)
1509 /* Caller must hold lock */
1511 RegionList covering;
1512 set<nframes_t> to_check;
1513 set<boost::shared_ptr<Region> > unique;
1516 to_check.insert (start);
1517 to_check.insert (end);
1519 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1521 /* find all/any regions that span start+end */
1523 switch ((*i)->coverage (start, end)) {
1527 case OverlapInternal:
1528 covering.push_back (*i);
1532 to_check.insert ((*i)->position());
1533 covering.push_back (*i);
1537 to_check.insert ((*i)->last_frame());
1538 covering.push_back (*i);
1541 case OverlapExternal:
1542 covering.push_back (*i);
1543 to_check.insert ((*i)->position());
1544 to_check.insert ((*i)->last_frame());
1548 /* don't go too far */
1550 if ((*i)->position() > end) {
1555 RegionList* rlist = new RegionList;
1557 /* find all the regions that cover each position .... */
1559 if (covering.size() == 1) {
1561 rlist->push_back (covering.front());
1565 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1569 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1571 if ((*x)->covers (*t)) {
1572 here.push_back (*x);
1576 RegionSortByLayer cmp;
1579 /* ... and get the top/transparent regions at "here" */
1581 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1585 if ((*c)->opaque()) {
1587 /* the other regions at this position are hidden by this one */
1594 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1595 rlist->push_back (*s);
1598 if (rlist->size() > 1) {
1599 /* now sort by time order */
1601 RegionSortByPosition cmp;
1609 Playlist::RegionList *
1610 Playlist::find_regions_at (nframes_t frame)
1612 /* Caller must hold lock */
1614 RegionList *rlist = new RegionList;
1616 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1617 if ((*i)->covers (frame)) {
1618 rlist->push_back (*i);
1625 Playlist::RegionList *
1626 Playlist::regions_touched (nframes_t start, nframes_t end)
1628 RegionLock rlock (this);
1629 RegionList *rlist = new RegionList;
1631 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1632 if ((*i)->coverage (start, end) != OverlapNone) {
1633 rlist->push_back (*i);
1641 Playlist::find_next_transient (nframes64_t from, int dir)
1643 RegionLock rlock (this);
1644 AnalysisFeatureList points;
1645 AnalysisFeatureList these_points;
1647 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1649 if ((*i)->last_frame() < from) {
1653 if ((*i)->first_frame() > from) {
1658 (*i)->get_transients (these_points);
1660 /* add first frame, just, err, because */
1662 these_points.push_back ((*i)->first_frame());
1664 points.insert (points.end(), these_points.begin(), these_points.end());
1665 these_points.clear ();
1668 if (points.empty()) {
1672 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1673 bool reached = false;
1676 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1681 if (reached && (*x) > from) {
1686 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1691 if (reached && (*x) < from) {
1700 boost::shared_ptr<Region>
1701 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1703 RegionLock rlock (this);
1704 boost::shared_ptr<Region> ret;
1705 nframes_t closest = max_frames;
1707 bool end_iter = false;
1709 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1714 boost::shared_ptr<Region> r = (*i);
1719 pos = r->first_frame ();
1722 pos = r->last_frame ();
1725 pos = r->sync_position ();
1726 // r->adjust_to_sync (r->first_frame());
1731 case 1: /* forwards */
1734 if ((distance = pos - frame) < closest) {
1743 default: /* backwards */
1746 if ((distance = frame - pos) < closest) {
1763 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1765 RegionLock rlock (this);
1767 nframes64_t closest = max_frames;
1768 nframes64_t ret = -1;
1772 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1774 boost::shared_ptr<Region> r = (*i);
1775 nframes64_t distance;
1777 if (r->first_frame() > frame) {
1779 distance = r->first_frame() - frame;
1781 if (distance < closest) {
1782 ret = r->first_frame();
1787 if (r->last_frame () > frame) {
1789 distance = r->last_frame () - frame;
1791 if (distance < closest) {
1792 ret = r->last_frame ();
1800 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1802 boost::shared_ptr<Region> r = (*i);
1803 nframes64_t distance;
1805 if (r->last_frame() < frame) {
1807 distance = frame - r->last_frame();
1809 if (distance < closest) {
1810 ret = r->last_frame();
1815 if (r->first_frame() < frame) {
1817 distance = frame - r->first_frame();
1819 if (distance < closest) {
1820 ret = r->first_frame();
1830 /***********************************************************************/
1836 Playlist::mark_session_dirty ()
1838 if (!in_set_state && !holding_state ()) {
1839 _session.set_dirty();
1844 Playlist::set_state (const XMLNode& node, int version)
1848 XMLNodeConstIterator niter;
1849 XMLPropertyList plist;
1850 XMLPropertyConstIterator piter;
1852 boost::shared_ptr<Region> region;
1857 if (node.name() != "Playlist") {
1864 plist = node.properties();
1866 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1870 if (prop->name() == X_("name")) {
1871 _name = prop->value();
1872 } else if (prop->name() == X_("orig_diskstream_id")) {
1873 _orig_diskstream_id = prop->value ();
1874 } else if (prop->name() == X_("frozen")) {
1875 _frozen = string_is_affirmative (prop->value());
1881 nlist = node.children();
1883 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1887 if (child->name() == "Region") {
1889 if ((prop = child->property ("id")) == 0) {
1890 error << _("region state node has no ID, ignored") << endmsg;
1894 ID id = prop->value ();
1896 if ((region = region_by_id (id))) {
1898 Change what_changed = Change (0);
1902 if (region->set_live_state (*child, version, what_changed, false)) {
1907 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
1910 error << _("Playlist: cannot create region from XML") << endmsg;
1914 add_region (region, region->position(), 1.0);
1916 // So that layer_op ordering doesn't get screwed up
1917 region->set_last_layer_op( region->layer());
1922 /* update dependents, which was not done during add_region_internal
1923 due to in_set_state being true
1926 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1927 check_dependents (*r, false);
1930 clear_pending (); // this makes thaw() do nothing
1932 notify_contents_changed ();
1935 first_set_state = false;
1940 Playlist::get_state()
1942 return state (true);
1946 Playlist::get_template()
1948 return state (false);
1951 /** @param full_state true to include regions in the returned state, otherwise false.
1954 Playlist::state (bool full_state)
1956 XMLNode *node = new XMLNode (X_("Playlist"));
1959 node->add_property (X_("name"), _name);
1960 node->add_property (X_("type"), _type.to_string());
1962 _orig_diskstream_id.print (buf, sizeof (buf));
1963 node->add_property (X_("orig_diskstream_id"), buf);
1964 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1967 RegionLock rlock (this, false);
1968 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1969 node->add_child_nocopy ((*i)->get_state());
1974 node->add_child_copy (*_extra_xml);
1981 Playlist::empty() const
1983 RegionLock rlock (const_cast<Playlist *>(this), false);
1984 return regions.empty();
1988 Playlist::n_regions() const
1990 RegionLock rlock (const_cast<Playlist *>(this), false);
1991 return regions.size();
1995 Playlist::get_maximum_extent () const
1997 RegionLock rlock (const_cast<Playlist *>(this), false);
1998 return _get_maximum_extent ();
2002 Playlist::_get_maximum_extent () const
2004 RegionList::const_iterator i;
2005 nframes_t max_extent = 0;
2008 for (i = regions.begin(); i != regions.end(); ++i) {
2009 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
2018 Playlist::bump_name (string name, Session &session)
2020 string newname = name;
2023 newname = bump_name_once (newname);
2024 } while (session.playlists->by_name (newname)!=NULL);
2031 Playlist::top_layer() const
2033 RegionLock rlock (const_cast<Playlist *> (this));
2036 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2037 top = max (top, (*i)->layer());
2043 Playlist::set_edit_mode (EditMode mode)
2048 /********************
2050 ********************/
2053 Playlist::relayer ()
2055 bool changed = false;
2057 /* Build up a new list of regions on each layer, stored in a set of lists
2058 each of which represent some period of time on some layer. The idea
2059 is to avoid having to search the entire region list to establish whether
2060 each region overlaps another */
2062 /* how many pieces to divide this playlist's time up into */
2063 int const divisions = 512;
2065 /* find the start and end positions of the regions on this playlist */
2066 nframes_t start = UINT_MAX;
2068 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2069 start = min (start, (*i)->position());
2070 end = max (end, (*i)->position() + (*i)->length());
2073 /* hence the size of each time division */
2074 double const division_size = (end - start) / double (divisions);
2076 vector<vector<RegionList> > layers;
2077 layers.push_back (vector<RegionList> (divisions));
2079 /* we want to go through regions from desired lowest to desired highest layer,
2080 which depends on the layer model
2083 RegionList copy = regions;
2085 /* sort according to the model and the layering mode that we're in */
2087 if (_explicit_relayering) {
2089 copy.sort (RegionSortByLayerWithPending ());
2091 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2093 copy.sort (RegionSortByLastLayerOp ());
2097 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2099 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2100 (*i)->set_pending_explicit_relayer (false);
2102 /* find the time divisions that this region covers */
2103 int const start_division = floor ( ((*i)->position() - start) / division_size);
2104 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2105 if (end_division == divisions) {
2109 assert (end_division < divisions);
2111 /* find the lowest layer that this region can go on */
2112 size_t j = layers.size();
2114 /* try layer j - 1; it can go on if it overlaps no other region
2115 that is already on that layer
2118 bool overlap = false;
2119 for (int k = start_division; k <= end_division; ++k) {
2120 RegionList::iterator l = layers[j-1][k].begin ();
2121 while (l != layers[j-1][k].end()) {
2122 if ((*l)->overlap_equivalent (*i)) {
2135 /* overlap, so we must use layer j */
2142 if (j == layers.size()) {
2143 /* we need a new layer for this region */
2144 layers.push_back (vector<RegionList> (divisions));
2147 /* put a reference to this region in each of the divisions that it exists in */
2148 for (int k = start_division; k <= end_division; ++k) {
2149 layers[j][k].push_back (*i);
2152 if ((*i)->layer() != j) {
2156 (*i)->set_layer (j);
2160 notify_layering_changed ();
2164 /* XXX these layer functions are all deprecated */
2167 Playlist::raise_region (boost::shared_ptr<Region> region)
2169 uint32_t rsz = regions.size();
2170 layer_t target = region->layer() + 1U;
2172 if (target >= rsz) {
2173 /* its already at the effective top */
2177 move_region_to_layer (target, region, 1);
2181 Playlist::lower_region (boost::shared_ptr<Region> region)
2183 if (region->layer() == 0) {
2184 /* its already at the bottom */
2188 layer_t target = region->layer() - 1U;
2190 move_region_to_layer (target, region, -1);
2194 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2196 /* does nothing useful if layering mode is later=higher */
2197 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2198 (_session.config.get_layer_model() == AddHigher)) {
2199 timestamp_layer_op (region);
2205 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2207 /* does nothing useful if layering mode is later=higher */
2208 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2209 (_session.config.get_layer_model() == AddHigher)) {
2210 region->set_last_layer_op (0);
2216 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2218 RegionList::iterator i;
2219 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2220 list<LayerInfo> layerinfo;
2224 RegionLock rlock (const_cast<Playlist *> (this));
2226 for (i = regions.begin(); i != regions.end(); ++i) {
2234 /* region is moving up, move all regions on intermediate layers
2238 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2239 dest = (*i)->layer() - 1;
2246 /* region is moving down, move all regions on intermediate layers
2250 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2251 dest = (*i)->layer() + 1;
2261 newpair.second = dest;
2263 layerinfo.push_back (newpair);
2267 /* now reset the layers without holding the region lock */
2269 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2270 x->first->set_layer (x->second);
2273 region->set_layer (target_layer);
2276 /* now check all dependents */
2278 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2279 check_dependents (x->first, false);
2282 check_dependents (region, false);
2289 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2291 RegionList::iterator i;
2298 RegionLock rlock (const_cast<Playlist *> (this));
2300 for (i = regions.begin(); i != regions.end(); ++i) {
2302 if ((*i)->position() >= start) {
2306 if ((*i)->last_frame() > max_frames - distance) {
2307 new_pos = max_frames - (*i)->length();
2309 new_pos = (*i)->position() + distance;
2314 if ((*i)->position() > distance) {
2315 new_pos = (*i)->position() - distance;
2321 (*i)->set_position (new_pos, this);
2329 notify_length_changed ();
2334 boost::shared_ptr<Region>
2335 Playlist::find_region (const ID& id) const
2337 RegionLock rlock (const_cast<Playlist*> (this));
2339 /* searches all regions currently in use by the playlist */
2341 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2342 if ((*i)->id() == id) {
2347 return boost::shared_ptr<Region> ();
2350 boost::shared_ptr<Region>
2351 Playlist::region_by_id (ID id)
2353 /* searches all regions ever added to this playlist */
2355 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2356 if ((*i)->id() == id) {
2360 return boost::shared_ptr<Region> ();
2364 Playlist::dump () const
2366 boost::shared_ptr<Region> r;
2368 cerr << "Playlist \"" << _name << "\" " << endl
2369 << regions.size() << " regions "
2372 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2374 cerr << " " << r->name() << " ["
2375 << r->start() << "+" << r->length()
2385 Playlist::set_frozen (bool yn)
2391 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2393 // struct timeval tv;
2394 // gettimeofday (&tv, 0);
2395 region->set_last_layer_op (++layer_op_counter);
2400 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2405 if (region->locked()) {
2412 RegionLock rlock (const_cast<Playlist*> (this));
2417 RegionList::iterator next;
2419 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2420 if ((*i) == region) {
2424 if (next != regions.end()) {
2426 if ((*next)->locked()) {
2430 if ((*next)->position() != region->last_frame() + 1) {
2431 /* they didn't used to touch, so after shuffle,
2432 just have them swap positions.
2434 new_pos = (*next)->position();
2436 /* they used to touch, so after shuffle,
2437 make sure they still do. put the earlier
2438 region where the later one will end after
2441 new_pos = region->position() + (*next)->length();
2444 (*next)->set_position (region->position(), this);
2445 region->set_position (new_pos, this);
2447 /* avoid a full sort */
2449 regions.erase (i); // removes the region from the list */
2451 regions.insert (next, region); // adds it back after next
2460 RegionList::iterator prev = regions.end();
2462 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2463 if ((*i) == region) {
2465 if (prev != regions.end()) {
2467 if ((*prev)->locked()) {
2471 if (region->position() != (*prev)->last_frame() + 1) {
2472 /* they didn't used to touch, so after shuffle,
2473 just have them swap positions.
2475 new_pos = region->position();
2477 /* they used to touch, so after shuffle,
2478 make sure they still do. put the earlier
2479 one where the later one will end after
2481 new_pos = (*prev)->position() + region->length();
2484 region->set_position ((*prev)->position(), this);
2485 (*prev)->set_position (new_pos, this);
2487 /* avoid a full sort */
2489 regions.erase (i); // remove region
2490 regions.insert (prev, region); // insert region before prev
2506 check_dependents (region, false);
2508 notify_contents_changed();
2514 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2516 RegionLock rlock (const_cast<Playlist*> (this));
2518 if (regions.size() > 1) {
2526 Playlist::update_after_tempo_map_change ()
2528 RegionLock rlock (const_cast<Playlist*> (this));
2529 RegionList copy (regions);
2533 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2534 (*i)->update_position_after_tempo_map_change ();
2541 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2543 RegionLock rl (this, false);
2544 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2550 Playlist::set_explicit_relayering (bool e)
2552 if (e == false && _explicit_relayering == true) {
2554 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2555 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2556 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2557 at this point would keep regions on the same layers.
2559 From then on in, it's just you and your towel.
2562 RegionLock rl (this);
2563 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2564 (*i)->set_last_layer_op ((*i)->layer ());
2568 _explicit_relayering = e;
2573 Playlist::has_region_at (nframes64_t const p) const
2575 RegionLock (const_cast<Playlist *> (this));
2577 RegionList::const_iterator i = regions.begin ();
2578 while (i != regions.end() && !(*i)->covers (p)) {
2582 return (i != regions.end());