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, framepos_t start, framecnt_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 framepos_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 frameoffset_t offset = 0;
169 framepos_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);
211 plist.add (Properties::start, offset);
212 plist.add (Properties::length, len);
213 plist.add (Properties::name, new_name);
214 plist.add (Properties::layer, region->layer());
216 new_region = RegionFactory::RegionFactory::create (region, plist);
218 add_region_internal (new_region, position);
222 first_set_state = false;
224 /* this constructor does NOT notify others (session) */
231 InUse (true); /* EMIT SIGNAL */
242 InUse (false); /* EMIT SIGNAL */
247 Playlist::copy_regions (RegionList& newlist) const
249 RegionLock rlock (const_cast<Playlist *> (this));
251 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
252 newlist.push_back (RegionFactory::RegionFactory::create (*i));
257 Playlist::init (bool hide)
259 g_atomic_int_set (&block_notifications, 0);
260 g_atomic_int_set (&ignore_state_changes, 0);
261 pending_contents_change = false;
262 pending_length = false;
263 pending_layering = false;
264 first_set_state = true;
271 _edit_mode = Config->get_edit_mode();
273 in_partition = false;
275 _read_data_count = 0;
277 layer_op_counter = 0;
279 _explicit_relayering = false;
281 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
284 Playlist::~Playlist ()
286 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
289 RegionLock rl (this);
291 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
292 (*i)->set_playlist (boost::shared_ptr<Playlist>());
296 /* GoingAway must be emitted by derived classes */
300 Playlist::set_name (const string& str)
302 /* in a typical situation, a playlist is being used
303 by one diskstream and also is referenced by the
304 Session. if there are more references than that,
305 then don't change the name.
311 return SessionObject::set_name(str);
315 /***********************************************************************
316 CHANGE NOTIFICATION HANDLING
318 Notifications must be delayed till the region_lock is released. This
319 is necessary because handlers for the signals may need to acquire
320 the lock (e.g. to read from the playlist).
321 ***********************************************************************/
326 delay_notifications ();
327 g_atomic_int_inc (&ignore_state_changes);
333 g_atomic_int_dec_and_test (&ignore_state_changes);
334 release_notifications ();
339 Playlist::delay_notifications ()
341 g_atomic_int_inc (&block_notifications);
342 freeze_length = _get_maximum_extent();
346 Playlist::release_notifications ()
348 if (g_atomic_int_dec_and_test (&block_notifications)) {
349 flush_notifications ();
354 Playlist::notify_contents_changed ()
356 if (holding_state ()) {
357 pending_contents_change = true;
359 pending_contents_change = false;
360 cerr << _name << "send contents change @ " << get_microseconds() << endl;
361 ContentsChanged(); /* EMIT SIGNAL */
362 cerr << _name << "done with cc @ " << get_microseconds() << endl;
367 Playlist::notify_layering_changed ()
369 if (holding_state ()) {
370 pending_layering = true;
372 pending_layering = false;
373 cerr << _name << "send layering @ " << get_microseconds() << endl;
374 LayeringChanged(); /* EMIT SIGNAL */
375 cerr << _name << "done with layering @ " << get_microseconds() << endl;
380 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
382 if (holding_state ()) {
383 pending_removes.insert (r);
384 pending_contents_change = true;
385 pending_length = true;
387 /* this might not be true, but we have to act
388 as though it could be.
390 pending_length = false;
391 LengthChanged (); /* EMIT SIGNAL */
392 pending_contents_change = false;
393 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
394 ContentsChanged (); /* EMIT SIGNAL */
399 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
401 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
403 if (holding_state ()) {
405 pending_range_moves.push_back (move);
409 list< Evoral::RangeMove<framepos_t> > m;
417 Playlist::notify_region_added (boost::shared_ptr<Region> r)
419 /* the length change might not be true, but we have to act
420 as though it could be.
423 if (holding_state()) {
424 pending_adds.insert (r);
425 pending_contents_change = true;
426 pending_length = true;
428 pending_length = false;
429 LengthChanged (); /* EMIT SIGNAL */
430 pending_contents_change = false;
431 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
432 cerr << _name << "send3 contents changed @ " << get_microseconds() << endl;
433 ContentsChanged (); /* EMIT SIGNAL */
434 cerr << _name << "done contents changed @ " << get_microseconds() << endl;
439 Playlist::notify_length_changed ()
441 if (holding_state ()) {
442 pending_length = true;
444 pending_length = false;
445 LengthChanged(); /* EMIT SIGNAL */
446 pending_contents_change = false;
447 cerr << _name << "send4 contents change @ " << get_microseconds() << endl;
448 ContentsChanged (); /* EMIT SIGNAL */
449 cerr << _name << "done contents change @ " << get_microseconds() << endl;
454 Playlist::flush_notifications ()
456 set<boost::shared_ptr<Region> > dependent_checks_needed;
457 set<boost::shared_ptr<Region> >::iterator s;
458 uint32_t regions_changed = false;
459 bool check_length = false;
460 framecnt_t old_length = 0;
468 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
469 regions_changed = true;
470 if (!pending_length) {
471 old_length = _get_maximum_extent ();
476 /* we have no idea what order the regions ended up in pending
477 bounds (it could be based on selection order, for example).
478 so, to preserve layering in the "most recently moved is higher"
479 model, sort them by existing layer, then timestamp them.
482 // RegionSortByLayer cmp;
483 // pending_bounds.sort (cmp);
485 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
486 if (_session.config.get_layer_model() == MoveAddHigher) {
487 timestamp_layer_op (*r);
489 dependent_checks_needed.insert (*r);
492 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
493 remove_dependents (*s);
494 cerr << _name << " sends RegionRemoved\n";
495 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
498 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
499 cerr << _name << " sends RegionAdded\n";
500 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
501 dependent_checks_needed.insert (*s);
505 if (old_length != _get_maximum_extent()) {
506 pending_length = true;
507 cerr << _name << " length has changed\n";
511 if (pending_length || (freeze_length != _get_maximum_extent())) {
512 pending_length = false;
513 cerr << _name << " sends LengthChanged\n";
514 LengthChanged(); /* EMIT SIGNAL */
517 if (regions_changed || pending_contents_change) {
521 pending_contents_change = false;
522 cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
523 ContentsChanged (); /* EMIT SIGNAL */
524 cerr << _name << "done contents change @ " << get_microseconds() << endl;
527 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
528 check_dependents (*s, false);
531 if (!pending_range_moves.empty ()) {
532 cerr << _name << " sends RangesMoved\n";
533 RangesMoved (pending_range_moves);
542 Playlist::clear_pending ()
544 pending_adds.clear ();
545 pending_removes.clear ();
546 pending_bounds.clear ();
547 pending_range_moves.clear ();
548 pending_contents_change = false;
549 pending_length = false;
552 /*************************************************************
554 *************************************************************/
557 Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
559 RegionLock rlock (this);
560 times = fabs (times);
562 int itimes = (int) floor (times);
564 framepos_t pos = position;
566 if (times == 1 && auto_partition){
567 partition(pos, (pos + region->length()), true);
571 add_region_internal (region, pos);
572 pos += region->length();
577 /* note that itimes can be zero if we being asked to just
578 insert a single fraction of the region.
581 for (int i = 0; i < itimes; ++i) {
582 boost::shared_ptr<Region> copy = RegionFactory::create (region);
583 add_region_internal (copy, pos);
584 pos += region->length();
587 framecnt_t length = 0;
589 if (floor (times) != times) {
590 length = (framecnt_t) floor (region->length() * (times - floor (times)));
592 _session.region_name (name, region->name(), false);
597 plist.add (Properties::start, 0);
598 plist.add (Properties::length, length);
599 plist.add (Properties::name, name);
600 plist.add (Properties::layer, region->layer());
602 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
603 add_region_internal (sub, pos);
607 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
611 Playlist::set_region_ownership ()
613 RegionLock rl (this);
614 RegionList::iterator i;
615 boost::weak_ptr<Playlist> pl (shared_from_this());
617 for (i = regions.begin(); i != regions.end(); ++i) {
618 (*i)->set_playlist (pl);
623 Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
625 if (region->data_type() != _type){
629 RegionSortByPosition cmp;
631 framecnt_t old_length = 0;
633 if (!holding_state()) {
634 old_length = _get_maximum_extent();
637 if (!first_set_state) {
638 boost::shared_ptr<Playlist> foo (shared_from_this());
639 region->set_playlist (boost::weak_ptr<Playlist>(foo));
642 region->set_position (position, this);
644 timestamp_layer_op (region);
646 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
647 all_regions.insert (region);
649 possibly_splice_unlocked (position, region->length(), region);
651 if (!holding_state () && !in_set_state) {
652 /* layers get assigned from XML state */
656 /* we need to notify the existence of new region before checking dependents. Ick. */
658 notify_region_added (region);
660 if (!holding_state ()) {
662 check_dependents (region, false);
664 if (old_length != _get_maximum_extent()) {
665 notify_length_changed ();
669 region->StateChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
675 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
677 RegionLock rlock (this);
679 bool old_sp = _splicing;
682 remove_region_internal (old);
683 add_region_internal (newr, pos);
687 possibly_splice_unlocked (pos, old->length() - newr->length());
691 Playlist::remove_region (boost::shared_ptr<Region> region)
693 RegionLock rlock (this);
694 remove_region_internal (region);
698 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
700 RegionList::iterator i;
701 framecnt_t old_length = 0;
704 if (!holding_state()) {
705 old_length = _get_maximum_extent();
710 region->set_playlist (boost::weak_ptr<Playlist>());
713 /* XXX should probably freeze here .... */
715 for (i = regions.begin(); i != regions.end(); ++i) {
718 framepos_t pos = (*i)->position();
719 framecnt_t distance = (*i)->length();
723 possibly_splice_unlocked (pos, -distance);
725 if (!holding_state ()) {
727 remove_dependents (region);
729 if (old_length != _get_maximum_extent()) {
730 notify_length_changed ();
734 notify_region_removed (region);
740 /* XXX and thaw ... */
746 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
748 if (Config->get_use_overlap_equivalency()) {
749 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
750 if ((*i)->overlap_equivalent (other)) {
751 results.push_back ((*i));
755 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
756 if ((*i)->equivalent (other)) {
757 results.push_back ((*i));
764 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
766 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
768 if ((*i) && (*i)->region_list_equivalent (other)) {
769 results.push_back (*i);
775 Playlist::partition (framepos_t start, framepos_t end, bool cut)
779 partition_internal (start, end, cut, thawlist);
781 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
787 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
789 RegionList new_regions;
792 RegionLock rlock (this);
794 boost::shared_ptr<Region> region;
795 boost::shared_ptr<Region> current;
797 RegionList::iterator tmp;
799 framepos_t pos1, pos2, pos3, pos4;
803 /* need to work from a copy, because otherwise the regions we add during the process
804 get operated on as well.
807 RegionList copy = regions;
809 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
816 if (current->first_frame() >= start && current->last_frame() < end) {
819 remove_region_internal (current);
825 /* coverage will return OverlapStart if the start coincides
826 with the end point. we do not partition such a region,
827 so catch this special case.
830 if (current->first_frame() >= end) {
834 if ((overlap = current->coverage (start, end)) == OverlapNone) {
838 pos1 = current->position();
841 pos4 = current->last_frame();
843 if (overlap == OverlapInternal) {
844 /* split: we need 3 new regions, the front, middle and end.
845 cut: we need 2 regions, the front and end.
850 ---------------*************************------------
853 ---------------*****++++++++++++++++====------------
855 ---------------*****----------------====------------
860 /* "middle" ++++++ */
862 _session.region_name (new_name, current->name(), false);
866 plist.add (Properties::start, pos2 - pos1);
867 plist.add (Properties::length, pos3 - pos2);
868 plist.add (Properties::name, new_name);
869 plist.add (Properties::layer, regions.size());
870 plist.add (Properties::automatic, true);
871 plist.add (Properties::left_of_split, true);
872 plist.add (Properties::right_of_split, true);
874 region = RegionFactory::create (current, plist);
875 add_region_internal (region, start);
876 new_regions.push_back (region);
881 _session.region_name (new_name, current->name(), false);
885 plist.add (Properties::start, pos3 - pos1);
886 plist.add (Properties::length, pos4 - pos3);
887 plist.add (Properties::name, new_name);
888 plist.add (Properties::layer, regions.size());
889 plist.add (Properties::automatic, true);
890 plist.add (Properties::right_of_split, true);
892 region = RegionFactory::create (current, plist);
894 add_region_internal (region, end);
895 new_regions.push_back (region);
900 thawlist.push_back (current);
901 current->trim_end (pos2, this);
903 } else if (overlap == OverlapEnd) {
907 ---------------*************************------------
910 ---------------**************+++++++++++------------
912 ---------------**************-----------------------
919 _session.region_name (new_name, current->name(), false);
923 plist.add (Properties::start, pos2 - pos1);
924 plist.add (Properties::length, pos4 - pos2);
925 plist.add (Properties::name, new_name);
926 plist.add (Properties::layer, regions.size());
927 plist.add (Properties::automatic, true);
928 plist.add (Properties::left_of_split, true);
930 region = RegionFactory::create (current, plist);
932 add_region_internal (region, start);
933 new_regions.push_back (region);
939 thawlist.push_back (current);
940 current->trim_end (pos2, this);
942 } else if (overlap == OverlapStart) {
944 /* split: we need 2 regions: the front and the end.
945 cut: just trim current to skip the cut area
950 ---------------*************************------------
954 ---------------****+++++++++++++++++++++------------
956 -------------------*********************------------
962 _session.region_name (new_name, current->name(), false);
966 plist.add (Properties::start, 0);
967 plist.add (Properties::length, pos3 - pos1);
968 plist.add (Properties::name, new_name);
969 plist.add (Properties::layer, regions.size());
970 plist.add (Properties::automatic, true);
971 plist.add (Properties::right_of_split, true);
973 region = RegionFactory::create (current, plist);
975 add_region_internal (region, pos1);
976 new_regions.push_back (region);
982 thawlist.push_back (current);
983 current->trim_front (pos3, this);
984 } else if (overlap == OverlapExternal) {
986 /* split: no split required.
987 cut: remove the region.
992 ---------------*************************------------
996 ---------------*************************------------
998 ----------------------------------------------------
1003 remove_region_internal (current);
1006 new_regions.push_back (current);
1010 in_partition = false;
1013 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1014 check_dependents (*i, false);
1018 boost::shared_ptr<Playlist>
1019 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1021 boost::shared_ptr<Playlist> ret;
1022 boost::shared_ptr<Playlist> pl;
1025 if (ranges.empty()) {
1026 return boost::shared_ptr<Playlist>();
1029 start = ranges.front().start;
1031 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1033 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1035 if (i == ranges.begin()) {
1039 /* paste the next section into the nascent playlist,
1040 offset to reflect the start of the first range we
1044 ret->paste (pl, (*i).start - start, 1.0f);
1051 boost::shared_ptr<Playlist>
1052 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1054 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1055 return cut_copy (pmf, ranges, result_is_hidden);
1058 boost::shared_ptr<Playlist>
1059 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1061 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1062 return cut_copy (pmf, ranges, result_is_hidden);
1065 boost::shared_ptr<Playlist>
1066 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1068 boost::shared_ptr<Playlist> the_copy;
1069 RegionList thawlist;
1072 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1073 string new_name = _name;
1077 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1078 return boost::shared_ptr<Playlist>();
1081 partition_internal (start, start+cnt-1, true, thawlist);
1083 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1090 boost::shared_ptr<Playlist>
1091 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1095 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1096 string new_name = _name;
1100 cnt = min (_get_maximum_extent() - start, cnt);
1101 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1105 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1107 times = fabs (times);
1108 framecnt_t old_length;
1111 RegionLock rl1 (this);
1112 RegionLock rl2 (other.get());
1114 old_length = _get_maximum_extent();
1116 int itimes = (int) floor (times);
1117 framepos_t pos = position;
1118 framecnt_t shift = other->_get_maximum_extent();
1119 layer_t top_layer = regions.size();
1122 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1123 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1125 /* put these new regions on top of all existing ones, but preserve
1126 the ordering they had in the original playlist.
1129 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1130 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1136 /* XXX shall we handle fractional cases at some point? */
1138 if (old_length != _get_maximum_extent()) {
1139 notify_length_changed ();
1150 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1152 times = fabs (times);
1154 RegionLock rl (this);
1155 int itimes = (int) floor (times);
1156 framepos_t pos = position;
1159 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1160 add_region_internal (copy, pos);
1161 pos += region->length();
1164 if (floor (times) != times) {
1165 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1167 _session.region_name (name, region->name(), false);
1172 plist.add (Properties::start, 0);
1173 plist.add (Properties::length, length);
1174 plist.add (Properties::name, name);
1176 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1177 add_region_internal (sub, pos);
1183 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1185 RegionLock rlock (this);
1186 RegionList copy (regions);
1189 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1191 if ((*r)->last_frame() < at) {
1196 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1197 /* intersected region */
1198 if (!move_intersected) {
1203 /* do not move regions glued to music time - that
1204 has to be done separately.
1207 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1208 fixup.push_back (*r);
1212 (*r)->set_position ((*r)->position() + distance, this);
1215 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1216 (*r)->recompute_position_from_lock_style ();
1221 Playlist::split (framepos_t at)
1223 RegionLock rlock (this);
1224 RegionList copy (regions);
1226 /* use a copy since this operation can modify the region list
1229 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1230 _split_region (*r, at);
1235 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1237 RegionLock rl (this);
1238 _split_region (region, playlist_position);
1242 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1244 if (!region->covers (playlist_position)) {
1248 if (region->position() == playlist_position ||
1249 region->last_frame() == playlist_position) {
1253 boost::shared_ptr<Region> left;
1254 boost::shared_ptr<Region> right;
1255 frameoffset_t before;
1256 frameoffset_t after;
1260 /* split doesn't change anything about length, so don't try to splice */
1262 bool old_sp = _splicing;
1265 before = playlist_position - region->position();
1266 after = region->length() - before;
1268 _session.region_name (before_name, region->name(), false);
1273 plist.add (Properties::start, 0);
1274 plist.add (Properties::length, before);
1275 plist.add (Properties::name, before_name);
1276 plist.add (Properties::left_of_split, true);
1278 left = RegionFactory::create (region, plist);
1281 _session.region_name (after_name, region->name(), false);
1286 plist.add (Properties::start, before);
1287 plist.add (Properties::length, after);
1288 plist.add (Properties::name, after_name);
1289 plist.add (Properties::right_of_split, true);
1291 right = RegionFactory::create (region, plist);
1294 add_region_internal (left, region->position());
1295 add_region_internal (right, region->position() + before);
1297 uint64_t orig_layer_op = region->last_layer_op();
1298 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1299 if ((*i)->last_layer_op() > orig_layer_op) {
1300 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1304 left->set_last_layer_op ( orig_layer_op );
1305 right->set_last_layer_op ( orig_layer_op + 1);
1309 finalize_split_region (region, left, right);
1311 remove_region_internal (region);
1317 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1319 if (_splicing || in_set_state) {
1320 /* don't respond to splicing moves or state setting */
1324 if (_edit_mode == Splice) {
1325 splice_locked (at, distance, exclude);
1330 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1332 if (_splicing || in_set_state) {
1333 /* don't respond to splicing moves or state setting */
1337 if (_edit_mode == Splice) {
1338 splice_unlocked (at, distance, exclude);
1343 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1346 RegionLock rl (this);
1347 core_splice (at, distance, exclude);
1352 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1354 core_splice (at, distance, exclude);
1358 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1362 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1364 if (exclude && (*i) == exclude) {
1368 if ((*i)->position() >= at) {
1369 framepos_t new_pos = (*i)->position() + distance;
1372 } else if (new_pos >= max_frames - (*i)->length()) {
1373 new_pos = max_frames - (*i)->length();
1376 (*i)->set_position (new_pos, this);
1382 notify_length_changed ();
1386 Playlist::region_bounds_changed (PropertyChange what_changed, boost::shared_ptr<Region> region)
1388 if (in_set_state || _splicing || _nudging || _shuffling) {
1392 if (what_changed & ARDOUR::PositionChanged) {
1394 /* remove it from the list then add it back in
1395 the right place again.
1398 RegionSortByPosition cmp;
1400 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1402 if (i == regions.end()) {
1403 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1404 _name, region->name())
1410 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1413 if (what_changed & PropertyChange (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1415 frameoffset_t delta = 0;
1417 if (what_changed & ARDOUR::PositionChanged) {
1418 delta = region->position() - region->last_position();
1421 if (what_changed & ARDOUR::LengthChanged) {
1422 delta += region->length() - region->last_length();
1426 possibly_splice (region->last_position() + region->last_length(), delta, region);
1429 if (holding_state ()) {
1430 pending_bounds.push_back (region);
1432 if (_session.config.get_layer_model() == MoveAddHigher) {
1433 /* it moved or changed length, so change the timestamp */
1434 timestamp_layer_op (region);
1437 notify_length_changed ();
1439 check_dependents (region, false);
1445 Playlist::region_changed_proxy (PropertyChange what_changed, boost::weak_ptr<Region> weak_region)
1447 boost::shared_ptr<Region> region (weak_region.lock());
1453 /* this makes a virtual call to the right kind of playlist ... */
1455 region_changed (what_changed, region);
1459 Playlist::region_changed (PropertyChange what_changed, boost::shared_ptr<Region> region)
1461 PropertyChange our_interests = PropertyChange (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1464 if (in_set_state || in_flush) {
1468 if (what_changed & BoundsChanged) {
1469 region_bounds_changed (what_changed, region);
1470 save = !(_splicing || _nudging);
1473 if ((what_changed & our_interests) &&
1474 !(what_changed & PropertyChange (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1475 check_dependents (region, false);
1478 if (what_changed & PropertyChange (ARDOUR::PositionChanged)) {
1479 notify_region_moved (region);
1483 /* don't notify about layer changes, since we are the only object that can initiate
1484 them, and we notify in ::relayer()
1487 if (what_changed & our_interests) {
1495 Playlist::drop_regions ()
1497 RegionLock rl (this);
1499 all_regions.clear ();
1503 Playlist::clear (bool with_signals)
1506 RegionLock rl (this);
1508 region_state_changed_connections.drop_connections ();
1510 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1511 pending_removes.insert (*i);
1518 pending_length = false;
1520 pending_contents_change = false;
1521 cerr << _name << "send2 contents change @ " << get_microseconds() << endl;
1523 cerr << _name << "done with contents changed @ " << get_microseconds() << endl;
1528 /***********************************************************************
1530 **********************************************************************/
1532 Playlist::RegionList *
1533 Playlist::regions_at (framepos_t frame)
1536 RegionLock rlock (this);
1537 return find_regions_at (frame);
1540 boost::shared_ptr<Region>
1541 Playlist::top_region_at (framepos_t frame)
1544 RegionLock rlock (this);
1545 RegionList *rlist = find_regions_at (frame);
1546 boost::shared_ptr<Region> region;
1548 if (rlist->size()) {
1549 RegionSortByLayer cmp;
1551 region = rlist->back();
1558 boost::shared_ptr<Region>
1559 Playlist::top_unmuted_region_at (framepos_t frame)
1562 RegionLock rlock (this);
1563 RegionList *rlist = find_regions_at (frame);
1565 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1567 RegionList::iterator tmp = i;
1570 if ((*i)->muted()) {
1577 boost::shared_ptr<Region> region;
1579 if (rlist->size()) {
1580 RegionSortByLayer cmp;
1582 region = rlist->back();
1589 Playlist::RegionList*
1590 Playlist::regions_to_read (framepos_t start, framepos_t end)
1592 /* Caller must hold lock */
1594 RegionList covering;
1595 set<framepos_t> to_check;
1596 set<boost::shared_ptr<Region> > unique;
1599 to_check.insert (start);
1600 to_check.insert (end);
1602 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1604 /* find all/any regions that span start+end */
1606 switch ((*i)->coverage (start, end)) {
1610 case OverlapInternal:
1611 covering.push_back (*i);
1615 to_check.insert ((*i)->position());
1616 covering.push_back (*i);
1620 to_check.insert ((*i)->last_frame());
1621 covering.push_back (*i);
1624 case OverlapExternal:
1625 covering.push_back (*i);
1626 to_check.insert ((*i)->position());
1627 to_check.insert ((*i)->last_frame());
1631 /* don't go too far */
1633 if ((*i)->position() > end) {
1638 RegionList* rlist = new RegionList;
1640 /* find all the regions that cover each position .... */
1642 if (covering.size() == 1) {
1644 rlist->push_back (covering.front());
1648 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1652 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1654 if ((*x)->covers (*t)) {
1655 here.push_back (*x);
1659 RegionSortByLayer cmp;
1662 /* ... and get the top/transparent regions at "here" */
1664 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1668 if ((*c)->opaque()) {
1670 /* the other regions at this position are hidden by this one */
1677 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1678 rlist->push_back (*s);
1681 if (rlist->size() > 1) {
1682 /* now sort by time order */
1684 RegionSortByPosition cmp;
1692 Playlist::RegionList *
1693 Playlist::find_regions_at (framepos_t frame)
1695 /* Caller must hold lock */
1697 RegionList *rlist = new RegionList;
1699 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1700 if ((*i)->covers (frame)) {
1701 rlist->push_back (*i);
1708 Playlist::RegionList *
1709 Playlist::regions_touched (framepos_t start, framepos_t end)
1711 RegionLock rlock (this);
1712 RegionList *rlist = new RegionList;
1714 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1715 if ((*i)->coverage (start, end) != OverlapNone) {
1716 rlist->push_back (*i);
1724 Playlist::find_next_transient (framepos_t from, int dir)
1726 RegionLock rlock (this);
1727 AnalysisFeatureList points;
1728 AnalysisFeatureList these_points;
1730 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1732 if ((*i)->last_frame() < from) {
1736 if ((*i)->first_frame() > from) {
1741 (*i)->get_transients (these_points);
1743 /* add first frame, just, err, because */
1745 these_points.push_back ((*i)->first_frame());
1747 points.insert (points.end(), these_points.begin(), these_points.end());
1748 these_points.clear ();
1751 if (points.empty()) {
1755 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1756 bool reached = false;
1759 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1764 if (reached && (*x) > from) {
1769 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1774 if (reached && (*x) < from) {
1783 boost::shared_ptr<Region>
1784 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1786 RegionLock rlock (this);
1787 boost::shared_ptr<Region> ret;
1788 framepos_t closest = max_frames;
1790 bool end_iter = false;
1792 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1796 frameoffset_t distance;
1797 boost::shared_ptr<Region> r = (*i);
1802 pos = r->first_frame ();
1805 pos = r->last_frame ();
1808 pos = r->sync_position ();
1809 // r->adjust_to_sync (r->first_frame());
1814 case 1: /* forwards */
1817 if ((distance = pos - frame) < closest) {
1826 default: /* backwards */
1829 if ((distance = frame - pos) < closest) {
1846 Playlist::find_next_region_boundary (framepos_t frame, int dir)
1848 RegionLock rlock (this);
1850 framepos_t closest = max_frames;
1851 framepos_t ret = -1;
1855 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1857 boost::shared_ptr<Region> r = (*i);
1858 frameoffset_t distance;
1860 if (r->first_frame() > frame) {
1862 distance = r->first_frame() - frame;
1864 if (distance < closest) {
1865 ret = r->first_frame();
1870 if (r->last_frame () > frame) {
1872 distance = r->last_frame () - frame;
1874 if (distance < closest) {
1875 ret = r->last_frame ();
1883 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1885 boost::shared_ptr<Region> r = (*i);
1886 frameoffset_t distance;
1888 if (r->last_frame() < frame) {
1890 distance = frame - r->last_frame();
1892 if (distance < closest) {
1893 ret = r->last_frame();
1898 if (r->first_frame() < frame) {
1900 distance = frame - r->first_frame();
1902 if (distance < closest) {
1903 ret = r->first_frame();
1913 /***********************************************************************/
1919 Playlist::mark_session_dirty ()
1921 if (!in_set_state && !holding_state ()) {
1922 _session.set_dirty();
1927 Playlist::set_state (const XMLNode& node, int version)
1931 XMLNodeConstIterator niter;
1932 XMLPropertyList plist;
1933 XMLPropertyConstIterator piter;
1935 boost::shared_ptr<Region> region;
1940 if (node.name() != "Playlist") {
1947 plist = node.properties();
1949 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1953 if (prop->name() == X_("name")) {
1954 _name = prop->value();
1955 } else if (prop->name() == X_("orig_diskstream_id")) {
1956 _orig_diskstream_id = prop->value ();
1957 } else if (prop->name() == X_("frozen")) {
1958 _frozen = string_is_affirmative (prop->value());
1964 nlist = node.children();
1966 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1970 if (child->name() == "Region") {
1972 if ((prop = child->property ("id")) == 0) {
1973 error << _("region state node has no ID, ignored") << endmsg;
1977 ID id = prop->value ();
1979 if ((region = region_by_id (id))) {
1983 if (region->set_state (*child, version)) {
1988 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
1991 error << _("Playlist: cannot create region from XML") << endmsg;
1995 add_region (region, region->position(), 1.0);
1997 // So that layer_op ordering doesn't get screwed up
1998 region->set_last_layer_op( region->layer());
2003 /* update dependents, which was not done during add_region_internal
2004 due to in_set_state being true
2007 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2008 check_dependents (*r, false);
2011 clear_pending (); // this makes thaw() do nothing
2013 notify_contents_changed ();
2016 first_set_state = false;
2021 Playlist::get_state()
2023 return state (true);
2027 Playlist::get_template()
2029 return state (false);
2032 /** @param full_state true to include regions in the returned state, otherwise false.
2035 Playlist::state (bool full_state)
2037 XMLNode *node = new XMLNode (X_("Playlist"));
2040 node->add_property (X_("name"), _name);
2041 node->add_property (X_("type"), _type.to_string());
2043 _orig_diskstream_id.print (buf, sizeof (buf));
2044 node->add_property (X_("orig_diskstream_id"), buf);
2045 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2048 RegionLock rlock (this, false);
2049 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2050 node->add_child_nocopy ((*i)->get_state());
2055 node->add_child_copy (*_extra_xml);
2062 Playlist::empty() const
2064 RegionLock rlock (const_cast<Playlist *>(this), false);
2065 return regions.empty();
2069 Playlist::n_regions() const
2071 RegionLock rlock (const_cast<Playlist *>(this), false);
2072 return regions.size();
2076 Playlist::get_maximum_extent () const
2078 RegionLock rlock (const_cast<Playlist *>(this), false);
2079 return _get_maximum_extent ();
2083 Playlist::_get_maximum_extent () const
2085 RegionList::const_iterator i;
2086 framecnt_t max_extent = 0;
2089 for (i = regions.begin(); i != regions.end(); ++i) {
2090 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
2099 Playlist::bump_name (string name, Session &session)
2101 string newname = name;
2104 newname = bump_name_once (newname);
2105 } while (session.playlists->by_name (newname)!=NULL);
2112 Playlist::top_layer() const
2114 RegionLock rlock (const_cast<Playlist *> (this));
2117 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2118 top = max (top, (*i)->layer());
2124 Playlist::set_edit_mode (EditMode mode)
2129 /********************
2131 ********************/
2134 Playlist::relayer ()
2136 bool changed = false;
2138 /* Build up a new list of regions on each layer, stored in a set of lists
2139 each of which represent some period of time on some layer. The idea
2140 is to avoid having to search the entire region list to establish whether
2141 each region overlaps another */
2143 /* how many pieces to divide this playlist's time up into */
2144 int const divisions = 512;
2146 /* find the start and end positions of the regions on this playlist */
2147 framepos_t start = UINT_MAX;
2149 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2150 start = min (start, (*i)->position());
2151 end = max (end, (*i)->position() + (*i)->length());
2154 /* hence the size of each time division */
2155 double const division_size = (end - start) / double (divisions);
2157 vector<vector<RegionList> > layers;
2158 layers.push_back (vector<RegionList> (divisions));
2160 /* we want to go through regions from desired lowest to desired highest layer,
2161 which depends on the layer model
2164 RegionList copy = regions;
2166 /* sort according to the model and the layering mode that we're in */
2168 if (_explicit_relayering) {
2170 copy.sort (RegionSortByLayerWithPending ());
2172 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2174 copy.sort (RegionSortByLastLayerOp ());
2178 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2180 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2181 (*i)->set_pending_explicit_relayer (false);
2183 /* find the time divisions that this region covers */
2184 int const start_division = floor ( ((*i)->position() - start) / division_size);
2185 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2186 if (end_division == divisions) {
2190 assert (end_division < divisions);
2192 /* find the lowest layer that this region can go on */
2193 size_t j = layers.size();
2195 /* try layer j - 1; it can go on if it overlaps no other region
2196 that is already on that layer
2199 bool overlap = false;
2200 for (int k = start_division; k <= end_division; ++k) {
2201 RegionList::iterator l = layers[j-1][k].begin ();
2202 while (l != layers[j-1][k].end()) {
2203 if ((*l)->overlap_equivalent (*i)) {
2216 /* overlap, so we must use layer j */
2223 if (j == layers.size()) {
2224 /* we need a new layer for this region */
2225 layers.push_back (vector<RegionList> (divisions));
2228 /* put a reference to this region in each of the divisions that it exists in */
2229 for (int k = start_division; k <= end_division; ++k) {
2230 layers[j][k].push_back (*i);
2233 if ((*i)->layer() != j) {
2237 (*i)->set_layer (j);
2241 notify_layering_changed ();
2245 /* XXX these layer functions are all deprecated */
2248 Playlist::raise_region (boost::shared_ptr<Region> region)
2250 uint32_t rsz = regions.size();
2251 layer_t target = region->layer() + 1U;
2253 if (target >= rsz) {
2254 /* its already at the effective top */
2258 move_region_to_layer (target, region, 1);
2262 Playlist::lower_region (boost::shared_ptr<Region> region)
2264 if (region->layer() == 0) {
2265 /* its already at the bottom */
2269 layer_t target = region->layer() - 1U;
2271 move_region_to_layer (target, region, -1);
2275 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2277 /* does nothing useful if layering mode is later=higher */
2278 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2279 (_session.config.get_layer_model() == AddHigher)) {
2280 timestamp_layer_op (region);
2286 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2288 /* does nothing useful if layering mode is later=higher */
2289 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2290 (_session.config.get_layer_model() == AddHigher)) {
2291 region->set_last_layer_op (0);
2297 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2299 RegionList::iterator i;
2300 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2301 list<LayerInfo> layerinfo;
2305 RegionLock rlock (const_cast<Playlist *> (this));
2307 for (i = regions.begin(); i != regions.end(); ++i) {
2315 /* region is moving up, move all regions on intermediate layers
2319 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2320 dest = (*i)->layer() - 1;
2327 /* region is moving down, move all regions on intermediate layers
2331 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2332 dest = (*i)->layer() + 1;
2342 newpair.second = dest;
2344 layerinfo.push_back (newpair);
2348 /* now reset the layers without holding the region lock */
2350 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2351 x->first->set_layer (x->second);
2354 region->set_layer (target_layer);
2357 /* now check all dependents */
2359 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2360 check_dependents (x->first, false);
2363 check_dependents (region, false);
2370 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2372 RegionList::iterator i;
2379 RegionLock rlock (const_cast<Playlist *> (this));
2381 for (i = regions.begin(); i != regions.end(); ++i) {
2383 if ((*i)->position() >= start) {
2387 if ((*i)->last_frame() > max_frames - distance) {
2388 new_pos = max_frames - (*i)->length();
2390 new_pos = (*i)->position() + distance;
2395 if ((*i)->position() > distance) {
2396 new_pos = (*i)->position() - distance;
2402 (*i)->set_position (new_pos, this);
2410 notify_length_changed ();
2415 boost::shared_ptr<Region>
2416 Playlist::find_region (const ID& id) const
2418 RegionLock rlock (const_cast<Playlist*> (this));
2420 /* searches all regions currently in use by the playlist */
2422 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2423 if ((*i)->id() == id) {
2428 return boost::shared_ptr<Region> ();
2431 boost::shared_ptr<Region>
2432 Playlist::region_by_id (ID id)
2434 /* searches all regions ever added to this playlist */
2436 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2437 if ((*i)->id() == id) {
2441 return boost::shared_ptr<Region> ();
2445 Playlist::dump () const
2447 boost::shared_ptr<Region> r;
2449 cerr << "Playlist \"" << _name << "\" " << endl
2450 << regions.size() << " regions "
2453 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2455 cerr << " " << r->name() << " ["
2456 << r->start() << "+" << r->length()
2466 Playlist::set_frozen (bool yn)
2472 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2474 // struct timeval tv;
2475 // gettimeofday (&tv, 0);
2476 region->set_last_layer_op (++layer_op_counter);
2481 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2486 if (region->locked()) {
2493 RegionLock rlock (const_cast<Playlist*> (this));
2498 RegionList::iterator next;
2500 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2501 if ((*i) == region) {
2505 if (next != regions.end()) {
2507 if ((*next)->locked()) {
2511 if ((*next)->position() != region->last_frame() + 1) {
2512 /* they didn't used to touch, so after shuffle,
2513 just have them swap positions.
2515 new_pos = (*next)->position();
2517 /* they used to touch, so after shuffle,
2518 make sure they still do. put the earlier
2519 region where the later one will end after
2522 new_pos = region->position() + (*next)->length();
2525 (*next)->set_position (region->position(), this);
2526 region->set_position (new_pos, this);
2528 /* avoid a full sort */
2530 regions.erase (i); // removes the region from the list */
2532 regions.insert (next, region); // adds it back after next
2541 RegionList::iterator prev = regions.end();
2543 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2544 if ((*i) == region) {
2546 if (prev != regions.end()) {
2548 if ((*prev)->locked()) {
2552 if (region->position() != (*prev)->last_frame() + 1) {
2553 /* they didn't used to touch, so after shuffle,
2554 just have them swap positions.
2556 new_pos = region->position();
2558 /* they used to touch, so after shuffle,
2559 make sure they still do. put the earlier
2560 one where the later one will end after
2562 new_pos = (*prev)->position() + region->length();
2565 region->set_position ((*prev)->position(), this);
2566 (*prev)->set_position (new_pos, this);
2568 /* avoid a full sort */
2570 regions.erase (i); // remove region
2571 regions.insert (prev, region); // insert region before prev
2587 check_dependents (region, false);
2589 notify_contents_changed();
2595 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2597 RegionLock rlock (const_cast<Playlist*> (this));
2599 if (regions.size() > 1) {
2607 Playlist::update_after_tempo_map_change ()
2609 RegionLock rlock (const_cast<Playlist*> (this));
2610 RegionList copy (regions);
2614 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2615 (*i)->update_position_after_tempo_map_change ();
2622 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2624 RegionLock rl (this, false);
2625 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2631 Playlist::set_explicit_relayering (bool e)
2633 if (e == false && _explicit_relayering == true) {
2635 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2636 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2637 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2638 at this point would keep regions on the same layers.
2640 From then on in, it's just you and your towel.
2643 RegionLock rl (this);
2644 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2645 (*i)->set_last_layer_op ((*i)->layer ());
2649 _explicit_relayering = e;
2654 Playlist::has_region_at (framepos_t const p) const
2656 RegionLock (const_cast<Playlist *> (this));
2658 RegionList::const_iterator i = regions.begin ();
2659 while (i != regions.end() && !(*i)->covers (p)) {
2663 return (i != regions.end());