2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sigc++/bind.h>
30 #include <pbd/failed_constructor.h>
31 #include <pbd/stl_delete.h>
32 #include <pbd/xml++.h>
33 #include <pbd/stacktrace.h>
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
39 #include <ardour/playlist_factory.h>
40 #include <ardour/transient_detector.h>
45 using namespace ARDOUR;
48 struct ShowMeTheList {
49 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
53 boost::shared_ptr<Playlist> playlist;
57 struct RegionSortByLayer {
58 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
59 return a->layer() < b->layer();
63 struct RegionSortByPosition {
64 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
65 return a->position() < b->position();
69 struct RegionSortByLastLayerOp {
70 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
71 return a->last_layer_op() < b->last_layer_op();
76 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
77 : SessionObject(sess, nom)
81 first_set_state = false;
86 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
87 : SessionObject(sess, "unnamed playlist")
90 const XMLProperty* prop = node.property("type");
91 assert(!prop || DataType(prop->value()) == _type);
94 _name = "unnamed"; /* reset by set_state */
96 /* set state called by derived class */
99 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
100 : SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
105 other->copy_regions (tmp);
109 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
110 add_region_internal( (*x), (*x)->position());
115 _splicing = other->_splicing;
116 _nudging = other->_nudging;
117 _edit_mode = other->_edit_mode;
120 first_set_state = false;
122 in_partition = false;
124 _read_data_count = 0;
125 _frozen = other->_frozen;
127 layer_op_counter = other->layer_op_counter;
128 freeze_length = other->freeze_length;
131 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
132 : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
134 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
136 nframes_t end = start + cnt - 1;
142 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
144 boost::shared_ptr<Region> region;
145 boost::shared_ptr<Region> new_region;
146 nframes_t offset = 0;
147 nframes_t position = 0;
154 overlap = region->coverage (start, end);
160 case OverlapInternal:
161 offset = start - region->position();
168 position = region->position() - start;
169 len = end - region->position();
173 offset = start - region->position();
175 len = region->length() - offset;
178 case OverlapExternal:
180 position = region->position() - start;
181 len = region->length();
185 _session.region_name (new_name, region->name(), false);
187 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
189 add_region_internal (new_region, position);
193 first_set_state = false;
195 /* this constructor does NOT notify others (session) */
202 InUse (true); /* EMIT SIGNAL */
213 InUse (false); /* EMIT SIGNAL */
218 Playlist::copy_regions (RegionList& newlist) const
220 RegionLock rlock (const_cast<Playlist *> (this));
222 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
223 newlist.push_back (RegionFactory::RegionFactory::create (*i));
228 Playlist::init (bool hide)
230 g_atomic_int_set (&block_notifications, 0);
231 g_atomic_int_set (&ignore_state_changes, 0);
232 pending_modified = false;
233 pending_length = false;
234 first_set_state = true;
241 _edit_mode = Config->get_edit_mode();
243 in_partition = false;
245 _read_data_count = 0;
247 layer_op_counter = 0;
250 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
253 Playlist::Playlist (const Playlist& pl)
254 : SessionObject(pl._session, pl._name)
255 , _type(pl.data_type())
257 fatal << _("playlist const copy constructor called") << endmsg;
260 Playlist::Playlist (Playlist& pl)
261 : SessionObject(pl._session, pl._name)
262 , _type(pl.data_type())
264 fatal << _("playlist non-const copy constructor called") << endmsg;
267 Playlist::~Playlist ()
270 RegionLock rl (this);
272 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
273 (*i)->set_playlist (boost::shared_ptr<Playlist>());
277 /* GoingAway must be emitted by derived classes */
281 Playlist::set_name (const string& str)
283 /* in a typical situation, a playlist is being used
284 by one diskstream and also is referenced by the
285 Session. if there are more references than that,
286 then don't change the name.
292 return SessionObject::set_name(str);
296 /***********************************************************************
297 CHANGE NOTIFICATION HANDLING
299 Notifications must be delayed till the region_lock is released. This
300 is necessary because handlers for the signals may need to acquire
301 the lock (e.g. to read from the playlist).
302 ***********************************************************************/
307 delay_notifications ();
308 g_atomic_int_inc (&ignore_state_changes);
314 g_atomic_int_dec_and_test (&ignore_state_changes);
315 release_notifications ();
320 Playlist::delay_notifications ()
322 g_atomic_int_inc (&block_notifications);
323 freeze_length = _get_maximum_extent();
327 Playlist::release_notifications ()
329 if (g_atomic_int_dec_and_test (&block_notifications)) {
330 flush_notifications ();
335 Playlist::notify_modified ()
337 if (holding_state ()) {
338 pending_modified = true;
340 pending_modified = false;
341 Modified(); /* EMIT SIGNAL */
346 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
348 if (holding_state ()) {
349 pending_removes.insert (r);
350 pending_modified = true;
351 pending_length = true;
353 /* this might not be true, but we have to act
354 as though it could be.
356 pending_length = false;
357 LengthChanged (); /* EMIT SIGNAL */
358 pending_modified = false;
359 Modified (); /* EMIT SIGNAL */
364 Playlist::notify_region_added (boost::shared_ptr<Region> r)
366 /* the length change might not be true, but we have to act
367 as though it could be.
370 if (holding_state()) {
371 pending_adds.insert (r);
372 pending_modified = true;
373 pending_length = true;
375 pending_length = false;
376 LengthChanged (); /* EMIT SIGNAL */
377 pending_modified = false;
378 Modified (); /* EMIT SIGNAL */
383 Playlist::notify_length_changed ()
385 if (holding_state ()) {
386 pending_length = true;
388 pending_length = false;
389 LengthChanged(); /* EMIT SIGNAL */
390 pending_modified = false;
391 Modified (); /* EMIT SIGNAL */
396 Playlist::flush_notifications ()
398 set<boost::shared_ptr<Region> > dependent_checks_needed;
399 set<boost::shared_ptr<Region> >::iterator s;
408 /* we have no idea what order the regions ended up in pending
409 bounds (it could be based on selection order, for example).
410 so, to preserve layering in the "most recently moved is higher"
411 model, sort them by existing layer, then timestamp them.
414 // RegionSortByLayer cmp;
415 // pending_bounds.sort (cmp);
417 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
418 if (Config->get_layer_model() == MoveAddHigher) {
419 timestamp_layer_op (*r);
421 pending_length = true;
422 dependent_checks_needed.insert (*r);
426 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
427 dependent_checks_needed.insert (*s);
431 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
432 remove_dependents (*s);
436 if ((freeze_length != _get_maximum_extent()) || pending_length) {
438 LengthChanged(); /* EMIT SIGNAL */
442 if (n || pending_modified) {
446 pending_modified = false;
447 Modified (); /* EMIT SIGNAL */
451 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
452 check_dependents (*s, false);
455 pending_adds.clear ();
456 pending_removes.clear ();
457 pending_bounds.clear ();
462 /*************************************************************
464 *************************************************************/
467 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
469 RegionLock rlock (this);
470 delay_notifications();
471 times = fabs (times);
473 int itimes = (int) floor (times);
475 nframes_t pos = position;
478 add_region_internal (region, pos);
479 pos += region->length();
484 /* note that itimes can be zero if we being asked to just
485 insert a single fraction of the region.
488 for (int i = 0; i < itimes; ++i) {
489 boost::shared_ptr<Region> copy = RegionFactory::create (region);
490 add_region_internal (copy, pos);
491 pos += region->length();
494 nframes_t length = 0;
496 if (floor (times) != times) {
497 length = (nframes_t) floor (region->length() * (times - floor (times)));
499 _session.region_name (name, region->name(), false);
500 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
501 add_region_internal (sub, pos);
505 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
506 release_notifications ();
510 Playlist::set_region_ownership ()
512 RegionLock rl (this);
513 RegionList::iterator i;
514 boost::weak_ptr<Playlist> pl (shared_from_this());
516 for (i = regions.begin(); i != regions.end(); ++i) {
517 (*i)->set_playlist (pl);
522 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
524 if (region->data_type() != _type)
527 RegionSortByPosition cmp;
528 nframes_t old_length = 0;
530 if (!holding_state()) {
531 old_length = _get_maximum_extent();
534 if (!first_set_state) {
535 boost::shared_ptr<Playlist> foo (shared_from_this());
536 region->set_playlist (boost::weak_ptr<Playlist>(foo));
539 region->set_position (position, this);
541 timestamp_layer_op (region);
543 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
544 all_regions.insert (region);
546 possibly_splice_unlocked (position, region->length(), region);
548 if (!holding_state () && !in_set_state) {
549 /* layers get assigned from XML state */
553 /* we need to notify the existence of new region before checking dependents. Ick. */
555 notify_region_added (region);
557 if (!holding_state ()) {
558 check_dependents (region, false);
559 if (old_length != _get_maximum_extent()) {
560 notify_length_changed ();
564 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
565 boost::weak_ptr<Region> (region)));
571 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
573 RegionLock rlock (this);
575 bool old_sp = _splicing;
578 remove_region_internal (old);
579 add_region_internal (newr, pos);
583 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
587 Playlist::remove_region (boost::shared_ptr<Region> region)
589 RegionLock rlock (this);
590 remove_region_internal (region);
594 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
596 RegionList::iterator i;
597 nframes_t old_length = 0;
599 if (!holding_state()) {
600 old_length = _get_maximum_extent();
605 region->set_playlist (boost::weak_ptr<Playlist>());
608 for (i = regions.begin(); i != regions.end(); ++i) {
611 nframes_t pos = (*i)->position();
612 nframes64_t distance = (*i)->length();
616 possibly_splice_unlocked (pos, -distance);
618 if (!holding_state ()) {
620 remove_dependents (region);
622 if (old_length != _get_maximum_extent()) {
623 notify_length_changed ();
627 notify_region_removed (region);
638 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
640 if (Config->get_use_overlap_equivalency()) {
641 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
642 if ((*i)->overlap_equivalent (other)) {
643 results.push_back ((*i));
647 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
648 if ((*i)->equivalent (other)) {
649 results.push_back ((*i));
656 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
658 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
660 if ((*i) && (*i)->region_list_equivalent (other)) {
661 results.push_back (*i);
667 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
671 partition_internal (start, end, false, thawlist);
673 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
674 (*i)->thaw ("separation");
679 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
681 RegionList new_regions;
684 RegionLock rlock (this);
685 boost::shared_ptr<Region> region;
686 boost::shared_ptr<Region> current;
688 RegionList::iterator tmp;
690 nframes_t pos1, pos2, pos3, pos4;
694 /* need to work from a copy, because otherwise the regions we add during the process
695 get operated on as well.
698 RegionList copy = regions;
700 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
707 if (current->first_frame() >= start && current->last_frame() < end) {
709 remove_region_internal (current);
714 /* coverage will return OverlapStart if the start coincides
715 with the end point. we do not partition such a region,
716 so catch this special case.
719 if (current->first_frame() >= end) {
723 if ((overlap = current->coverage (start, end)) == OverlapNone) {
727 pos1 = current->position();
730 pos4 = current->last_frame();
732 if (overlap == OverlapInternal) {
734 /* split: we need 3 new regions, the front, middle and end.
735 cut: we need 2 regions, the front and end.
740 ---------------*************************------------
743 ---------------*****++++++++++++++++====------------
745 ---------------*****----------------====------------
751 /* "middle" ++++++ */
753 _session.region_name (new_name, current->name(), false);
754 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
755 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
756 add_region_internal (region, start);
757 new_regions.push_back (region);
762 _session.region_name (new_name, current->name(), false);
763 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
764 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
766 add_region_internal (region, end);
767 new_regions.push_back (region);
772 thawlist.push_back (current);
773 current->trim_end (pos2, this);
775 } else if (overlap == OverlapEnd) {
779 ---------------*************************------------
782 ---------------**************+++++++++++------------
784 ---------------**************-----------------------
791 _session.region_name (new_name, current->name(), false);
792 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
793 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
794 add_region_internal (region, start);
795 new_regions.push_back (region);
801 thawlist.push_back (current);
802 current->trim_end (pos2, this);
804 } else if (overlap == OverlapStart) {
806 /* split: we need 2 regions: the front and the end.
807 cut: just trim current to skip the cut area
812 ---------------*************************------------
816 ---------------****+++++++++++++++++++++------------
818 -------------------*********************------------
825 _session.region_name (new_name, current->name(), false);
826 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
827 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
828 add_region_internal (region, pos1);
829 new_regions.push_back (region);
835 thawlist.push_back (current);
836 current->trim_front (pos3, this);
838 } else if (overlap == OverlapExternal) {
840 /* split: no split required.
841 cut: remove the region.
846 ---------------*************************------------
850 ---------------*************************------------
852 ----------------------------------------------------
857 remove_region_internal (current);
859 new_regions.push_back (current);
863 in_partition = false;
866 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
867 check_dependents (*i, false);
871 boost::shared_ptr<Playlist>
872 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
874 boost::shared_ptr<Playlist> ret;
875 boost::shared_ptr<Playlist> pl;
878 if (ranges.empty()) {
879 return boost::shared_ptr<Playlist>();
882 start = ranges.front().start;
884 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
886 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
888 if (i == ranges.begin()) {
892 /* paste the next section into the nascent playlist,
893 offset to reflect the start of the first range we
897 ret->paste (pl, (*i).start - start, 1.0f);
904 boost::shared_ptr<Playlist>
905 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
907 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
908 return cut_copy (pmf, ranges, result_is_hidden);
911 boost::shared_ptr<Playlist>
912 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
914 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
915 return cut_copy (pmf, ranges, result_is_hidden);
918 boost::shared_ptr<Playlist>
919 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
921 boost::shared_ptr<Playlist> the_copy;
925 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
926 string new_name = _name;
930 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
931 return boost::shared_ptr<Playlist>();
934 partition_internal (start, start+cnt-1, true, thawlist);
936 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
937 (*i)->thaw ("playlist cut");
943 boost::shared_ptr<Playlist>
944 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
948 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
949 string new_name = _name;
953 cnt = min (_get_maximum_extent() - start, cnt);
954 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
958 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
960 times = fabs (times);
961 nframes_t old_length;
964 RegionLock rl1 (this);
965 RegionLock rl2 (other.get());
967 old_length = _get_maximum_extent();
969 int itimes = (int) floor (times);
970 nframes_t pos = position;
971 nframes_t shift = other->_get_maximum_extent();
972 layer_t top_layer = regions.size();
975 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
976 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
978 /* put these new regions on top of all existing ones, but preserve
979 the ordering they had in the original playlist.
982 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
983 add_region_internal (copy_of_region, copy_of_region->position() + pos);
989 /* XXX shall we handle fractional cases at some point? */
991 if (old_length != _get_maximum_extent()) {
992 notify_length_changed ();
1003 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1005 times = fabs (times);
1007 RegionLock rl (this);
1008 int itimes = (int) floor (times);
1009 nframes_t pos = position;
1012 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1013 add_region_internal (copy, pos);
1014 pos += region->length();
1017 if (floor (times) != times) {
1018 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1020 _session.region_name (name, region->name(), false);
1021 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1022 add_region_internal (sub, pos);
1027 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1029 RegionLock rlock (this);
1030 RegionList copy (regions);
1033 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1035 if ((*r)->last_frame() < at) {
1040 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1041 /* intersected region */
1042 if (!move_intersected) {
1047 /* do not move regions glued to music time - that
1048 has to be done separately.
1051 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1052 fixup.push_back (*r);
1056 (*r)->set_position ((*r)->position() + distance, this);
1059 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1060 (*r)->recompute_position_from_lock_style ();
1065 Playlist::split (nframes64_t at)
1067 RegionLock rlock (this);
1068 RegionList copy (regions);
1070 /* use a copy since this operation can modify the region list
1073 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1074 _split_region (*r, at);
1079 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1081 RegionLock rl (this);
1082 _split_region (region, playlist_position);
1086 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1088 if (!region->covers (playlist_position)) {
1092 if (region->position() == playlist_position ||
1093 region->last_frame() == playlist_position) {
1097 boost::shared_ptr<Region> left;
1098 boost::shared_ptr<Region> right;
1104 /* split doesn't change anything about length, so don't try to splice */
1106 bool old_sp = _splicing;
1109 before = playlist_position - region->position();
1110 after = region->length() - before;
1112 _session.region_name (before_name, region->name(), false);
1113 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1115 _session.region_name (after_name, region->name(), false);
1116 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1118 add_region_internal (left, region->position());
1119 add_region_internal (right, region->position() + before);
1121 uint64_t orig_layer_op = region->last_layer_op();
1122 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1123 if ((*i)->last_layer_op() > orig_layer_op) {
1124 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1128 left->set_last_layer_op ( orig_layer_op );
1129 right->set_last_layer_op ( orig_layer_op + 1);
1133 finalize_split_region (region, left, right);
1135 remove_region_internal (region);
1141 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1143 if (_splicing || in_set_state) {
1144 /* don't respond to splicing moves or state setting */
1148 if (_edit_mode == Splice) {
1149 splice_locked (at, distance, exclude);
1154 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1156 if (_splicing || in_set_state) {
1157 /* don't respond to splicing moves or state setting */
1161 if (_edit_mode == Splice) {
1162 splice_unlocked (at, distance, exclude);
1167 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1170 RegionLock rl (this);
1171 core_splice (at, distance, exclude);
1176 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1178 core_splice (at, distance, exclude);
1182 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1186 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1188 if (exclude && (*i) == exclude) {
1192 if ((*i)->position() >= at) {
1193 nframes64_t new_pos = (*i)->position() + distance;
1196 } else if (new_pos >= max_frames - (*i)->length()) {
1197 new_pos = max_frames - (*i)->length();
1200 (*i)->set_position (new_pos, this);
1206 notify_length_changed ();
1210 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1212 if (in_set_state || _splicing || _nudging || _shuffling) {
1216 if (what_changed & ARDOUR::PositionChanged) {
1218 /* remove it from the list then add it back in
1219 the right place again.
1222 RegionSortByPosition cmp;
1224 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1226 if (i == regions.end()) {
1227 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1228 _name, region->name())
1234 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1237 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1239 nframes64_t delta = 0;
1241 if (what_changed & ARDOUR::PositionChanged) {
1242 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1245 if (what_changed & ARDOUR::LengthChanged) {
1246 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1250 possibly_splice (region->last_position() + region->last_length(), delta, region);
1253 if (holding_state ()) {
1254 pending_bounds.push_back (region);
1256 if (Config->get_layer_model() == MoveAddHigher) {
1257 /* it moved or changed length, so change the timestamp */
1258 timestamp_layer_op (region);
1261 notify_length_changed ();
1263 check_dependents (region, false);
1269 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1271 boost::shared_ptr<Region> region (weak_region.lock());
1278 /* this makes a virtual call to the right kind of playlist ... */
1280 region_changed (what_changed, region);
1284 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1286 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1289 if (in_set_state || in_flush) {
1294 if (what_changed & BoundsChanged) {
1295 region_bounds_changed (what_changed, region);
1296 save = !(_splicing || _nudging);
1299 if ((what_changed & our_interests) &&
1300 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1301 check_dependents (region, false);
1304 if (what_changed & our_interests) {
1313 Playlist::drop_regions ()
1315 RegionLock rl (this);
1317 all_regions.clear ();
1321 Playlist::clear (bool with_signals)
1324 RegionLock rl (this);
1325 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1326 pending_removes.insert (*i);
1332 pending_length = false;
1334 pending_modified = false;
1340 /***********************************************************************
1342 **********************************************************************/
1344 Playlist::RegionList *
1345 Playlist::regions_at (nframes_t frame)
1348 RegionLock rlock (this);
1349 return find_regions_at (frame);
1352 boost::shared_ptr<Region>
1353 Playlist::top_region_at (nframes_t frame)
1356 RegionLock rlock (this);
1357 RegionList *rlist = find_regions_at (frame);
1358 boost::shared_ptr<Region> region;
1360 if (rlist->size()) {
1361 RegionSortByLayer cmp;
1363 region = rlist->back();
1370 Playlist::RegionList*
1371 Playlist::regions_to_read (nframes_t start, nframes_t end)
1373 /* Caller must hold lock */
1375 RegionList covering;
1376 set<nframes_t> to_check;
1377 set<boost::shared_ptr<Region> > unique;
1380 to_check.insert (start);
1381 to_check.insert (end);
1383 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1385 /* find all/any regions that span start+end */
1387 switch ((*i)->coverage (start, end)) {
1391 case OverlapInternal:
1392 covering.push_back (*i);
1396 to_check.insert ((*i)->position());
1397 covering.push_back (*i);
1401 to_check.insert ((*i)->last_frame());
1402 covering.push_back (*i);
1405 case OverlapExternal:
1406 covering.push_back (*i);
1407 to_check.insert ((*i)->position());
1408 to_check.insert ((*i)->last_frame());
1412 /* don't go too far */
1414 if ((*i)->position() > end) {
1419 RegionList* rlist = new RegionList;
1421 /* find all the regions that cover each position .... */
1423 if (covering.size() == 1) {
1425 rlist->push_back (covering.front());
1429 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1433 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1435 if ((*x)->covers (*t)) {
1436 here.push_back (*x);
1440 RegionSortByLayer cmp;
1443 /* ... and get the top/transparent regions at "here" */
1445 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1449 if ((*c)->opaque()) {
1451 /* the other regions at this position are hidden by this one */
1458 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1459 rlist->push_back (*s);
1462 if (rlist->size() > 1) {
1463 /* now sort by time order */
1465 RegionSortByPosition cmp;
1473 Playlist::RegionList *
1474 Playlist::find_regions_at (nframes_t frame)
1476 /* Caller must hold lock */
1478 RegionList *rlist = new RegionList;
1480 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1481 if ((*i)->covers (frame)) {
1482 rlist->push_back (*i);
1489 Playlist::RegionList *
1490 Playlist::regions_touched (nframes_t start, nframes_t end)
1492 RegionLock rlock (this);
1493 RegionList *rlist = new RegionList;
1495 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1496 if ((*i)->coverage (start, end) != OverlapNone) {
1497 rlist->push_back (*i);
1505 Playlist::find_next_transient (nframes64_t from, int dir)
1507 RegionLock rlock (this);
1508 AnalysisFeatureList points;
1509 AnalysisFeatureList these_points;
1511 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1513 if ((*i)->last_frame() < from) {
1517 if ((*i)->first_frame() > from) {
1522 (*i)->get_transients (these_points);
1524 /* add first frame, just, err, because */
1526 these_points.push_back ((*i)->first_frame());
1528 points.insert (points.end(), these_points.begin(), these_points.end());
1529 these_points.clear ();
1532 if (points.empty()) {
1536 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1537 bool reached = false;
1540 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1545 if (reached && (*x) > from) {
1550 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1555 if (reached && (*x) < from) {
1564 boost::shared_ptr<Region>
1565 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1567 RegionLock rlock (this);
1568 boost::shared_ptr<Region> ret;
1569 nframes_t closest = max_frames;
1572 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1575 boost::shared_ptr<Region> r = (*i);
1580 pos = r->first_frame ();
1583 pos = r->last_frame ();
1586 pos = r->adjust_to_sync (r->first_frame());
1591 case 1: /* forwards */
1594 if ((distance = pos - frame) < closest) {
1602 default: /* backwards */
1605 if ((distance = frame - pos) < closest) {
1618 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1620 RegionLock rlock (this);
1622 nframes64_t closest = max_frames;
1623 nframes64_t ret = -1;
1627 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1629 boost::shared_ptr<Region> r = (*i);
1630 nframes64_t distance;
1631 nframes64_t end = r->position() + r->length();
1636 if (r->first_frame() > frame) {
1638 distance = r->first_frame() - frame;
1640 if (distance < closest) {
1641 ret = r->first_frame();
1649 distance = end - frame;
1651 if (distance < closest) {
1665 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1667 boost::shared_ptr<Region> r = (*i);
1668 nframes64_t distance;
1673 if (r->last_frame() < frame) {
1675 distance = frame - r->last_frame();
1677 if (distance < closest) {
1678 ret = r->last_frame();
1684 if (r->first_frame() < frame) {
1685 distance = frame - r->last_frame();
1687 if (distance < closest) {
1688 ret = r->first_frame();
1703 /***********************************************************************/
1708 Playlist::mark_session_dirty ()
1710 if (!in_set_state && !holding_state ()) {
1711 _session.set_dirty();
1716 Playlist::set_state (const XMLNode& node)
1720 XMLNodeConstIterator niter;
1721 XMLPropertyList plist;
1722 XMLPropertyConstIterator piter;
1724 boost::shared_ptr<Region> region;
1729 if (node.name() != "Playlist") {
1736 plist = node.properties();
1738 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1742 if (prop->name() == X_("name")) {
1743 _name = prop->value();
1744 } else if (prop->name() == X_("orig_diskstream_id")) {
1745 _orig_diskstream_id = prop->value ();
1746 } else if (prop->name() == X_("frozen")) {
1747 _frozen = (prop->value() == X_("yes"));
1753 nlist = node.children();
1755 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1759 if (child->name() == "Region") {
1761 if ((prop = child->property ("id")) == 0) {
1762 error << _("region state node has no ID, ignored") << endmsg;
1766 ID id = prop->value ();
1768 if ((region = region_by_id (id))) {
1770 Change what_changed = Change (0);
1772 if (region->set_live_state (*child, what_changed, true)) {
1773 error << _("Playlist: cannot reset region state from XML") << endmsg;
1777 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1778 error << _("Playlist: cannot create region from XML") << endmsg;
1782 add_region (region, region->position(), 1.0);
1784 // So that layer_op ordering doesn't get screwed up
1785 region->set_last_layer_op( region->layer());
1794 /* update dependents, which was not done during add_region_internal
1795 due to in_set_state being true
1798 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1799 check_dependents (*r, false);
1803 first_set_state = false;
1808 Playlist::get_state()
1814 Playlist::get_template()
1816 return state(false);
1820 Playlist::state (bool full_state)
1822 XMLNode *node = new XMLNode (X_("Playlist"));
1825 node->add_property (X_("name"), _name);
1826 node->add_property (X_("type"), _type.to_string());
1828 _orig_diskstream_id.print (buf, sizeof (buf));
1829 node->add_property (X_("orig_diskstream_id"), buf);
1830 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1833 RegionLock rlock (this, false);
1834 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1835 node->add_child_nocopy ((*i)->get_state());
1840 node->add_child_copy (*_extra_xml);
1847 Playlist::empty() const
1849 RegionLock rlock (const_cast<Playlist *>(this), false);
1850 return regions.empty();
1854 Playlist::n_regions() const
1856 RegionLock rlock (const_cast<Playlist *>(this), false);
1857 return regions.size();
1861 Playlist::get_maximum_extent () const
1863 RegionLock rlock (const_cast<Playlist *>(this), false);
1864 return _get_maximum_extent ();
1868 Playlist::_get_maximum_extent () const
1870 RegionList::const_iterator i;
1871 nframes_t max_extent = 0;
1874 for (i = regions.begin(); i != regions.end(); ++i) {
1875 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1884 Playlist::bump_name (string name, Session &session)
1886 string newname = name;
1889 newname = bump_name_once (newname);
1890 } while (session.playlist_by_name (newname)!=NULL);
1897 Playlist::top_layer() const
1899 RegionLock rlock (const_cast<Playlist *> (this));
1902 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1903 top = max (top, (*i)->layer());
1909 Playlist::set_edit_mode (EditMode mode)
1914 /********************
1916 ********************/
1919 Playlist::relayer ()
1921 /* don't send multiple Modified notifications
1922 when multiple regions are relayered.
1927 /* build up a new list of regions on each layer */
1929 std::vector<RegionList> layers;
1931 /* we want to go through regions from desired lowest to desired highest layer,
1932 which depends on the layer model
1935 RegionList copy = regions;
1937 /* sort according to the model */
1939 if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
1940 RegionSortByLastLayerOp cmp;
1944 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1946 /* find the lowest layer that this region can go on */
1947 size_t j = layers.size();
1949 /* try layer j - 1; it can go on if it overlaps no other region
1950 that is already on that layer
1952 RegionList::iterator k = layers[j - 1].begin();
1953 while (k != layers[j - 1].end()) {
1954 if ((*k)->overlap_equivalent (*i)) {
1960 if (k != layers[j - 1].end()) {
1961 /* no overlap, so we can use this layer */
1968 if (j == layers.size()) {
1969 /* we need a new layer for this region */
1970 layers.push_back (RegionList ());
1973 layers[j].push_back (*i);
1976 /* first pass: set up the layer numbers in the regions */
1977 for (size_t j = 0; j < layers.size(); ++j) {
1978 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
1979 (*i)->set_layer (j);
1983 /* sending Modified means that various kinds of layering
1984 models operate correctly at the GUI
1985 level. slightly inefficient, but only slightly.
1987 We force a Modified signal here in case no layers actually
1996 /* XXX these layer functions are all deprecated */
1999 Playlist::raise_region (boost::shared_ptr<Region> region)
2001 uint32_t rsz = regions.size();
2002 layer_t target = region->layer() + 1U;
2004 if (target >= rsz) {
2005 /* its already at the effective top */
2009 move_region_to_layer (target, region, 1);
2013 Playlist::lower_region (boost::shared_ptr<Region> region)
2015 if (region->layer() == 0) {
2016 /* its already at the bottom */
2020 layer_t target = region->layer() - 1U;
2022 move_region_to_layer (target, region, -1);
2026 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2028 /* does nothing useful if layering mode is later=higher */
2029 if ((Config->get_layer_model() == MoveAddHigher) ||
2030 (Config->get_layer_model() == AddHigher)) {
2031 timestamp_layer_op (region);
2037 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2039 /* does nothing useful if layering mode is later=higher */
2040 if ((Config->get_layer_model() == MoveAddHigher) ||
2041 (Config->get_layer_model() == AddHigher)) {
2042 region->set_last_layer_op (0);
2048 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2050 RegionList::iterator i;
2051 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2052 list<LayerInfo> layerinfo;
2056 RegionLock rlock (const_cast<Playlist *> (this));
2058 for (i = regions.begin(); i != regions.end(); ++i) {
2066 /* region is moving up, move all regions on intermediate layers
2070 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2071 dest = (*i)->layer() - 1;
2078 /* region is moving down, move all regions on intermediate layers
2082 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2083 dest = (*i)->layer() + 1;
2093 newpair.second = dest;
2095 layerinfo.push_back (newpair);
2099 /* now reset the layers without holding the region lock */
2101 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2102 x->first->set_layer (x->second);
2105 region->set_layer (target_layer);
2108 /* now check all dependents */
2110 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2111 check_dependents (x->first, false);
2114 check_dependents (region, false);
2121 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2123 RegionList::iterator i;
2130 RegionLock rlock (const_cast<Playlist *> (this));
2132 for (i = regions.begin(); i != regions.end(); ++i) {
2134 if ((*i)->position() >= start) {
2138 if ((*i)->last_frame() > max_frames - distance) {
2139 new_pos = max_frames - (*i)->length();
2141 new_pos = (*i)->position() + distance;
2146 if ((*i)->position() > distance) {
2147 new_pos = (*i)->position() - distance;
2153 (*i)->set_position (new_pos, this);
2161 notify_length_changed ();
2166 boost::shared_ptr<Region>
2167 Playlist::find_region (const ID& id) const
2169 RegionLock rlock (const_cast<Playlist*> (this));
2171 /* searches all regions currently in use by the playlist */
2173 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2174 if ((*i)->id() == id) {
2179 return boost::shared_ptr<Region> ();
2182 boost::shared_ptr<Region>
2183 Playlist::region_by_id (ID id)
2185 /* searches all regions ever added to this playlist */
2187 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2188 if ((*i)->id() == id) {
2192 return boost::shared_ptr<Region> ();
2196 Playlist::dump () const
2198 boost::shared_ptr<Region> r;
2200 cerr << "Playlist \"" << _name << "\" " << endl
2201 << regions.size() << " regions "
2204 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2206 cerr << " " << r->name() << " ["
2207 << r->start() << "+" << r->length()
2217 Playlist::set_frozen (bool yn)
2223 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2225 // struct timeval tv;
2226 // gettimeofday (&tv, 0);
2227 region->set_last_layer_op (++layer_op_counter);
2232 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2237 if (region->locked()) {
2244 RegionLock rlock (const_cast<Playlist*> (this));
2249 RegionList::iterator next;
2251 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2252 if ((*i) == region) {
2256 if (next != regions.end()) {
2258 if ((*next)->locked()) {
2262 if ((*next)->position() != region->last_frame() + 1) {
2263 /* they didn't used to touch, so after shuffle,
2264 just have them swap positions.
2266 new_pos = (*next)->position();
2268 /* they used to touch, so after shuffle,
2269 make sure they still do. put the earlier
2270 region where the later one will end after
2273 new_pos = region->position() + (*next)->length();
2276 (*next)->set_position (region->position(), this);
2277 region->set_position (new_pos, this);
2279 /* avoid a full sort */
2281 regions.erase (i); // removes the region from the list */
2283 regions.insert (next, region); // adds it back after next
2292 RegionList::iterator prev = regions.end();
2294 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2295 if ((*i) == region) {
2297 if (prev != regions.end()) {
2299 if ((*prev)->locked()) {
2303 if (region->position() != (*prev)->last_frame() + 1) {
2304 /* they didn't used to touch, so after shuffle,
2305 just have them swap positions.
2307 new_pos = region->position();
2309 /* they used to touch, so after shuffle,
2310 make sure they still do. put the earlier
2311 one where the later one will end after
2313 new_pos = (*prev)->position() + region->length();
2316 region->set_position ((*prev)->position(), this);
2317 (*prev)->set_position (new_pos, this);
2319 /* avoid a full sort */
2321 regions.erase (i); // remove region
2322 regions.insert (prev, region); // insert region before prev
2338 check_dependents (region, false);
2346 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2348 RegionLock rlock (const_cast<Playlist*> (this));
2350 if (regions.size() > 1) {
2358 Playlist::update_after_tempo_map_change ()
2360 RegionLock rlock (const_cast<Playlist*> (this));
2361 RegionList copy (regions);
2365 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2366 (*i)->update_position_after_tempo_map_change ();