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_moved (boost::shared_ptr<Region> r)
366 Evoral::RangeMove const move (r->last_position (), r->length (), r->position ());
368 if (holding_state ()) {
370 pending_range_moves.push_back (move);
374 Evoral::RangeMoveList m;
383 Playlist::notify_region_added (boost::shared_ptr<Region> r)
385 /* the length change might not be true, but we have to act
386 as though it could be.
389 if (holding_state()) {
390 pending_adds.insert (r);
391 pending_modified = true;
392 pending_length = true;
394 pending_length = false;
395 LengthChanged (); /* EMIT SIGNAL */
396 pending_modified = false;
397 Modified (); /* EMIT SIGNAL */
402 Playlist::notify_length_changed ()
404 if (holding_state ()) {
405 pending_length = true;
407 pending_length = false;
408 LengthChanged(); /* EMIT SIGNAL */
409 pending_modified = false;
410 Modified (); /* EMIT SIGNAL */
415 Playlist::flush_notifications ()
417 set<boost::shared_ptr<Region> > dependent_checks_needed;
418 set<boost::shared_ptr<Region> >::iterator s;
427 /* we have no idea what order the regions ended up in pending
428 bounds (it could be based on selection order, for example).
429 so, to preserve layering in the "most recently moved is higher"
430 model, sort them by existing layer, then timestamp them.
433 // RegionSortByLayer cmp;
434 // pending_bounds.sort (cmp);
436 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
437 if (Config->get_layer_model() == MoveAddHigher) {
438 timestamp_layer_op (*r);
440 pending_length = true;
441 dependent_checks_needed.insert (*r);
445 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
446 dependent_checks_needed.insert (*s);
450 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
451 remove_dependents (*s);
455 if ((freeze_length != _get_maximum_extent()) || pending_length) {
457 LengthChanged(); /* EMIT SIGNAL */
461 if (n || pending_modified) {
465 pending_modified = false;
466 Modified (); /* EMIT SIGNAL */
470 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
471 check_dependents (*s, false);
474 if (!pending_range_moves.empty ()) {
475 RangesMoved (pending_range_moves);
478 pending_adds.clear ();
479 pending_removes.clear ();
480 pending_bounds.clear ();
481 pending_range_moves.clear ();
486 /*************************************************************
488 *************************************************************/
491 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
493 RegionLock rlock (this);
494 times = fabs (times);
496 int itimes = (int) floor (times);
498 nframes_t pos = position;
501 add_region_internal (region, pos);
502 pos += region->length();
507 /* note that itimes can be zero if we being asked to just
508 insert a single fraction of the region.
511 for (int i = 0; i < itimes; ++i) {
512 boost::shared_ptr<Region> copy = RegionFactory::create (region);
513 add_region_internal (copy, pos);
514 pos += region->length();
517 nframes_t length = 0;
519 if (floor (times) != times) {
520 length = (nframes_t) floor (region->length() * (times - floor (times)));
522 _session.region_name (name, region->name(), false);
523 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
524 add_region_internal (sub, pos);
528 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
532 Playlist::set_region_ownership ()
534 RegionLock rl (this);
535 RegionList::iterator i;
536 boost::weak_ptr<Playlist> pl (shared_from_this());
538 for (i = regions.begin(); i != regions.end(); ++i) {
539 (*i)->set_playlist (pl);
544 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
546 if (region->data_type() != _type)
549 RegionSortByPosition cmp;
550 nframes_t old_length = 0;
552 if (!holding_state()) {
553 old_length = _get_maximum_extent();
556 if (!first_set_state) {
557 boost::shared_ptr<Playlist> foo (shared_from_this());
558 region->set_playlist (boost::weak_ptr<Playlist>(foo));
561 region->set_position (position, this);
563 timestamp_layer_op (region);
565 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
566 all_regions.insert (region);
568 possibly_splice_unlocked (position, region->length(), region);
570 if (!holding_state () && !in_set_state) {
571 /* layers get assigned from XML state */
575 /* we need to notify the existence of new region before checking dependents. Ick. */
577 notify_region_added (region);
579 if (!holding_state ()) {
580 check_dependents (region, false);
581 if (old_length != _get_maximum_extent()) {
582 notify_length_changed ();
586 region_state_changed_connections.push_back (
587 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
588 boost::weak_ptr<Region> (region)))
595 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
597 RegionLock rlock (this);
599 bool old_sp = _splicing;
602 remove_region_internal (old);
603 add_region_internal (newr, pos);
607 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
611 Playlist::remove_region (boost::shared_ptr<Region> region)
613 RegionLock rlock (this);
614 remove_region_internal (region);
618 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
620 RegionList::iterator i;
621 nframes_t old_length = 0;
623 if (!holding_state()) {
624 old_length = _get_maximum_extent();
629 region->set_playlist (boost::weak_ptr<Playlist>());
632 for (i = regions.begin(); i != regions.end(); ++i) {
635 nframes_t pos = (*i)->position();
636 nframes64_t distance = (*i)->length();
640 possibly_splice_unlocked (pos, -distance);
642 if (!holding_state ()) {
644 remove_dependents (region);
646 if (old_length != _get_maximum_extent()) {
647 notify_length_changed ();
651 notify_region_removed (region);
662 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
664 if (Config->get_use_overlap_equivalency()) {
665 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
666 if ((*i)->overlap_equivalent (other)) {
667 results.push_back ((*i));
671 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
672 if ((*i)->equivalent (other)) {
673 results.push_back ((*i));
680 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
682 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
684 if ((*i) && (*i)->region_list_equivalent (other)) {
685 results.push_back (*i);
691 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
695 partition_internal (start, end, false, thawlist);
697 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
698 (*i)->thaw ("separation");
703 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
705 RegionList new_regions;
708 RegionLock rlock (this);
709 boost::shared_ptr<Region> region;
710 boost::shared_ptr<Region> current;
712 RegionList::iterator tmp;
714 nframes_t pos1, pos2, pos3, pos4;
718 /* need to work from a copy, because otherwise the regions we add during the process
719 get operated on as well.
722 RegionList copy = regions;
724 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
731 if (current->first_frame() >= start && current->last_frame() < end) {
733 remove_region_internal (current);
738 /* coverage will return OverlapStart if the start coincides
739 with the end point. we do not partition such a region,
740 so catch this special case.
743 if (current->first_frame() >= end) {
747 if ((overlap = current->coverage (start, end)) == OverlapNone) {
751 pos1 = current->position();
754 pos4 = current->last_frame();
756 if (overlap == OverlapInternal) {
758 /* split: we need 3 new regions, the front, middle and end.
759 cut: we need 2 regions, the front and end.
764 ---------------*************************------------
767 ---------------*****++++++++++++++++====------------
769 ---------------*****----------------====------------
775 /* "middle" ++++++ */
777 _session.region_name (new_name, current->name(), false);
778 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
779 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
780 add_region_internal (region, start);
781 new_regions.push_back (region);
786 _session.region_name (new_name, current->name(), false);
787 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
788 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
790 add_region_internal (region, end);
791 new_regions.push_back (region);
796 thawlist.push_back (current);
797 current->trim_end (pos2, this);
799 } else if (overlap == OverlapEnd) {
803 ---------------*************************------------
806 ---------------**************+++++++++++------------
808 ---------------**************-----------------------
815 _session.region_name (new_name, current->name(), false);
816 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
817 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
818 add_region_internal (region, start);
819 new_regions.push_back (region);
825 thawlist.push_back (current);
826 current->trim_end (pos2, this);
828 } else if (overlap == OverlapStart) {
830 /* split: we need 2 regions: the front and the end.
831 cut: just trim current to skip the cut area
836 ---------------*************************------------
840 ---------------****+++++++++++++++++++++------------
842 -------------------*********************------------
849 _session.region_name (new_name, current->name(), false);
850 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
851 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
852 add_region_internal (region, pos1);
853 new_regions.push_back (region);
859 thawlist.push_back (current);
860 current->trim_front (pos3, this);
862 } else if (overlap == OverlapExternal) {
864 /* split: no split required.
865 cut: remove the region.
870 ---------------*************************------------
874 ---------------*************************------------
876 ----------------------------------------------------
881 remove_region_internal (current);
883 new_regions.push_back (current);
887 in_partition = false;
890 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
891 check_dependents (*i, false);
895 boost::shared_ptr<Playlist>
896 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
898 boost::shared_ptr<Playlist> ret;
899 boost::shared_ptr<Playlist> pl;
902 if (ranges.empty()) {
903 return boost::shared_ptr<Playlist>();
906 start = ranges.front().start;
908 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
910 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
912 if (i == ranges.begin()) {
916 /* paste the next section into the nascent playlist,
917 offset to reflect the start of the first range we
921 ret->paste (pl, (*i).start - start, 1.0f);
928 boost::shared_ptr<Playlist>
929 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
931 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
932 return cut_copy (pmf, ranges, result_is_hidden);
935 boost::shared_ptr<Playlist>
936 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
938 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
939 return cut_copy (pmf, ranges, result_is_hidden);
942 boost::shared_ptr<Playlist>
943 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
945 boost::shared_ptr<Playlist> the_copy;
949 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
950 string new_name = _name;
954 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
955 return boost::shared_ptr<Playlist>();
958 partition_internal (start, start+cnt-1, true, thawlist);
960 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
961 (*i)->thaw ("playlist cut");
967 boost::shared_ptr<Playlist>
968 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
972 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
973 string new_name = _name;
977 cnt = min (_get_maximum_extent() - start, cnt);
978 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
982 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
984 times = fabs (times);
985 nframes_t old_length;
988 RegionLock rl1 (this);
989 RegionLock rl2 (other.get());
991 old_length = _get_maximum_extent();
993 int itimes = (int) floor (times);
994 nframes_t pos = position;
995 nframes_t shift = other->_get_maximum_extent();
996 layer_t top_layer = regions.size();
999 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1000 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1002 /* put these new regions on top of all existing ones, but preserve
1003 the ordering they had in the original playlist.
1006 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1007 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1013 /* XXX shall we handle fractional cases at some point? */
1015 if (old_length != _get_maximum_extent()) {
1016 notify_length_changed ();
1027 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1029 times = fabs (times);
1031 RegionLock rl (this);
1032 int itimes = (int) floor (times);
1033 nframes_t pos = position;
1036 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1037 add_region_internal (copy, pos);
1038 pos += region->length();
1041 if (floor (times) != times) {
1042 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1044 _session.region_name (name, region->name(), false);
1045 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1046 add_region_internal (sub, pos);
1051 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1053 RegionLock rlock (this);
1054 RegionList copy (regions);
1057 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1059 if ((*r)->last_frame() < at) {
1064 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1065 /* intersected region */
1066 if (!move_intersected) {
1071 /* do not move regions glued to music time - that
1072 has to be done separately.
1075 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1076 fixup.push_back (*r);
1080 (*r)->set_position ((*r)->position() + distance, this);
1083 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1084 (*r)->recompute_position_from_lock_style ();
1089 Playlist::split (nframes64_t at)
1091 RegionLock rlock (this);
1092 RegionList copy (regions);
1094 /* use a copy since this operation can modify the region list
1097 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1098 _split_region (*r, at);
1103 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1105 RegionLock rl (this);
1106 _split_region (region, playlist_position);
1110 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1112 if (!region->covers (playlist_position)) {
1116 if (region->position() == playlist_position ||
1117 region->last_frame() == playlist_position) {
1121 boost::shared_ptr<Region> left;
1122 boost::shared_ptr<Region> right;
1128 /* split doesn't change anything about length, so don't try to splice */
1130 bool old_sp = _splicing;
1133 before = playlist_position - region->position();
1134 after = region->length() - before;
1136 _session.region_name (before_name, region->name(), false);
1137 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1139 _session.region_name (after_name, region->name(), false);
1140 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1142 add_region_internal (left, region->position());
1143 add_region_internal (right, region->position() + before);
1145 uint64_t orig_layer_op = region->last_layer_op();
1146 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1147 if ((*i)->last_layer_op() > orig_layer_op) {
1148 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1152 left->set_last_layer_op ( orig_layer_op );
1153 right->set_last_layer_op ( orig_layer_op + 1);
1157 finalize_split_region (region, left, right);
1159 remove_region_internal (region);
1165 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1167 if (_splicing || in_set_state) {
1168 /* don't respond to splicing moves or state setting */
1172 if (_edit_mode == Splice) {
1173 splice_locked (at, distance, exclude);
1178 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1180 if (_splicing || in_set_state) {
1181 /* don't respond to splicing moves or state setting */
1185 if (_edit_mode == Splice) {
1186 splice_unlocked (at, distance, exclude);
1191 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1194 RegionLock rl (this);
1195 core_splice (at, distance, exclude);
1200 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1202 core_splice (at, distance, exclude);
1206 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1210 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1212 if (exclude && (*i) == exclude) {
1216 if ((*i)->position() >= at) {
1217 nframes64_t new_pos = (*i)->position() + distance;
1220 } else if (new_pos >= max_frames - (*i)->length()) {
1221 new_pos = max_frames - (*i)->length();
1224 (*i)->set_position (new_pos, this);
1230 notify_length_changed ();
1234 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1236 if (in_set_state || _splicing || _nudging || _shuffling) {
1240 if (what_changed & ARDOUR::PositionChanged) {
1242 /* remove it from the list then add it back in
1243 the right place again.
1246 RegionSortByPosition cmp;
1248 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1250 if (i == regions.end()) {
1251 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1252 _name, region->name())
1258 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1261 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1263 nframes64_t delta = 0;
1265 if (what_changed & ARDOUR::PositionChanged) {
1266 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1269 if (what_changed & ARDOUR::LengthChanged) {
1270 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1274 possibly_splice (region->last_position() + region->last_length(), delta, region);
1277 if (holding_state ()) {
1278 pending_bounds.push_back (region);
1280 if (Config->get_layer_model() == MoveAddHigher) {
1281 /* it moved or changed length, so change the timestamp */
1282 timestamp_layer_op (region);
1285 notify_length_changed ();
1287 check_dependents (region, false);
1293 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1295 boost::shared_ptr<Region> region (weak_region.lock());
1302 /* this makes a virtual call to the right kind of playlist ... */
1304 region_changed (what_changed, region);
1308 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1310 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1313 if (in_set_state || in_flush) {
1317 if (what_changed & BoundsChanged) {
1318 region_bounds_changed (what_changed, region);
1319 save = !(_splicing || _nudging);
1322 if ((what_changed & our_interests) &&
1323 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1324 check_dependents (region, false);
1327 if (what_changed & Change (ARDOUR::PositionChanged)) {
1328 notify_region_moved (region);
1331 if (what_changed & our_interests) {
1339 Playlist::drop_regions ()
1341 RegionLock rl (this);
1343 all_regions.clear ();
1347 Playlist::clear (bool with_signals)
1350 RegionLock rl (this);
1353 std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
1354 i != region_state_changed_connections.end ();
1362 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1363 pending_removes.insert (*i);
1369 pending_length = false;
1371 pending_modified = false;
1377 /***********************************************************************
1379 **********************************************************************/
1381 Playlist::RegionList *
1382 Playlist::regions_at (nframes_t frame)
1385 RegionLock rlock (this);
1386 return find_regions_at (frame);
1389 boost::shared_ptr<Region>
1390 Playlist::top_region_at (nframes_t frame)
1393 RegionLock rlock (this);
1394 RegionList *rlist = find_regions_at (frame);
1395 boost::shared_ptr<Region> region;
1397 if (rlist->size()) {
1398 RegionSortByLayer cmp;
1400 region = rlist->back();
1407 Playlist::RegionList*
1408 Playlist::regions_to_read (nframes_t start, nframes_t end)
1410 /* Caller must hold lock */
1412 RegionList covering;
1413 set<nframes_t> to_check;
1414 set<boost::shared_ptr<Region> > unique;
1417 to_check.insert (start);
1418 to_check.insert (end);
1420 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1422 /* find all/any regions that span start+end */
1424 switch ((*i)->coverage (start, end)) {
1428 case OverlapInternal:
1429 covering.push_back (*i);
1433 to_check.insert ((*i)->position());
1434 covering.push_back (*i);
1438 to_check.insert ((*i)->last_frame());
1439 covering.push_back (*i);
1442 case OverlapExternal:
1443 covering.push_back (*i);
1444 to_check.insert ((*i)->position());
1445 to_check.insert ((*i)->last_frame());
1449 /* don't go too far */
1451 if ((*i)->position() > end) {
1456 RegionList* rlist = new RegionList;
1458 /* find all the regions that cover each position .... */
1460 if (covering.size() == 1) {
1462 rlist->push_back (covering.front());
1466 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1470 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1472 if ((*x)->covers (*t)) {
1473 here.push_back (*x);
1477 RegionSortByLayer cmp;
1480 /* ... and get the top/transparent regions at "here" */
1482 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1486 if ((*c)->opaque()) {
1488 /* the other regions at this position are hidden by this one */
1495 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1496 rlist->push_back (*s);
1499 if (rlist->size() > 1) {
1500 /* now sort by time order */
1502 RegionSortByPosition cmp;
1510 Playlist::RegionList *
1511 Playlist::find_regions_at (nframes_t frame)
1513 /* Caller must hold lock */
1515 RegionList *rlist = new RegionList;
1517 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1518 if ((*i)->covers (frame)) {
1519 rlist->push_back (*i);
1526 Playlist::RegionList *
1527 Playlist::regions_touched (nframes_t start, nframes_t end)
1529 RegionLock rlock (this);
1530 RegionList *rlist = new RegionList;
1532 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1533 if ((*i)->coverage (start, end) != OverlapNone) {
1534 rlist->push_back (*i);
1542 Playlist::find_next_transient (nframes64_t from, int dir)
1544 RegionLock rlock (this);
1545 AnalysisFeatureList points;
1546 AnalysisFeatureList these_points;
1548 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1550 if ((*i)->last_frame() < from) {
1554 if ((*i)->first_frame() > from) {
1559 (*i)->get_transients (these_points);
1561 /* add first frame, just, err, because */
1563 these_points.push_back ((*i)->first_frame());
1565 points.insert (points.end(), these_points.begin(), these_points.end());
1566 these_points.clear ();
1569 if (points.empty()) {
1573 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1574 bool reached = false;
1577 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1582 if (reached && (*x) > from) {
1587 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1592 if (reached && (*x) < from) {
1601 boost::shared_ptr<Region>
1602 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1604 RegionLock rlock (this);
1605 boost::shared_ptr<Region> ret;
1606 nframes_t closest = max_frames;
1609 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1612 boost::shared_ptr<Region> r = (*i);
1617 pos = r->first_frame ();
1620 pos = r->last_frame ();
1623 pos = r->adjust_to_sync (r->first_frame());
1628 case 1: /* forwards */
1631 if ((distance = pos - frame) < closest) {
1639 default: /* backwards */
1642 if ((distance = frame - pos) < closest) {
1655 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1657 RegionLock rlock (this);
1659 nframes64_t closest = max_frames;
1660 nframes64_t ret = -1;
1664 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1666 boost::shared_ptr<Region> r = (*i);
1667 nframes64_t distance;
1668 nframes64_t end = r->position() + r->length();
1673 if (r->first_frame() > frame) {
1675 distance = r->first_frame() - frame;
1677 if (distance < closest) {
1678 ret = r->first_frame();
1686 distance = end - frame;
1688 if (distance < closest) {
1702 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1704 boost::shared_ptr<Region> r = (*i);
1705 nframes64_t distance;
1710 if (r->last_frame() < frame) {
1712 distance = frame - r->last_frame();
1714 if (distance < closest) {
1715 ret = r->last_frame();
1721 if (r->first_frame() < frame) {
1722 distance = frame - r->last_frame();
1724 if (distance < closest) {
1725 ret = r->first_frame();
1740 /***********************************************************************/
1745 Playlist::mark_session_dirty ()
1747 if (!in_set_state && !holding_state ()) {
1748 _session.set_dirty();
1753 Playlist::set_state (const XMLNode& node)
1757 XMLNodeConstIterator niter;
1758 XMLPropertyList plist;
1759 XMLPropertyConstIterator piter;
1761 boost::shared_ptr<Region> region;
1766 if (node.name() != "Playlist") {
1773 plist = node.properties();
1775 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1779 if (prop->name() == X_("name")) {
1780 _name = prop->value();
1781 } else if (prop->name() == X_("orig_diskstream_id")) {
1782 _orig_diskstream_id = prop->value ();
1783 } else if (prop->name() == X_("frozen")) {
1784 _frozen = (prop->value() == X_("yes"));
1790 nlist = node.children();
1792 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1796 if (child->name() == "Region") {
1798 if ((prop = child->property ("id")) == 0) {
1799 error << _("region state node has no ID, ignored") << endmsg;
1803 ID id = prop->value ();
1805 if ((region = region_by_id (id))) {
1807 Change what_changed = Change (0);
1809 if (region->set_live_state (*child, what_changed, true)) {
1810 error << _("Playlist: cannot reset region state from XML") << endmsg;
1814 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1815 error << _("Playlist: cannot create region from XML") << endmsg;
1819 add_region (region, region->position(), 1.0);
1821 // So that layer_op ordering doesn't get screwed up
1822 region->set_last_layer_op( region->layer());
1831 /* update dependents, which was not done during add_region_internal
1832 due to in_set_state being true
1835 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1836 check_dependents (*r, false);
1840 first_set_state = false;
1845 Playlist::get_state()
1851 Playlist::get_template()
1853 return state(false);
1857 Playlist::state (bool full_state)
1859 XMLNode *node = new XMLNode (X_("Playlist"));
1862 node->add_property (X_("name"), _name);
1863 node->add_property (X_("type"), _type.to_string());
1865 _orig_diskstream_id.print (buf, sizeof (buf));
1866 node->add_property (X_("orig_diskstream_id"), buf);
1867 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1870 RegionLock rlock (this, false);
1871 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1872 node->add_child_nocopy ((*i)->get_state());
1877 node->add_child_copy (*_extra_xml);
1884 Playlist::empty() const
1886 RegionLock rlock (const_cast<Playlist *>(this), false);
1887 return regions.empty();
1891 Playlist::n_regions() const
1893 RegionLock rlock (const_cast<Playlist *>(this), false);
1894 return regions.size();
1898 Playlist::get_maximum_extent () const
1900 RegionLock rlock (const_cast<Playlist *>(this), false);
1901 return _get_maximum_extent ();
1905 Playlist::_get_maximum_extent () const
1907 RegionList::const_iterator i;
1908 nframes_t max_extent = 0;
1911 for (i = regions.begin(); i != regions.end(); ++i) {
1912 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1921 Playlist::bump_name (string name, Session &session)
1923 string newname = name;
1926 newname = bump_name_once (newname);
1927 } while (session.playlist_by_name (newname)!=NULL);
1934 Playlist::top_layer() const
1936 RegionLock rlock (const_cast<Playlist *> (this));
1939 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1940 top = max (top, (*i)->layer());
1946 Playlist::set_edit_mode (EditMode mode)
1951 /********************
1953 ********************/
1956 Playlist::relayer ()
1958 /* don't send multiple Modified notifications
1959 when multiple regions are relayered.
1964 /* build up a new list of regions on each layer */
1966 std::vector<RegionList> layers;
1968 /* we want to go through regions from desired lowest to desired highest layer,
1969 which depends on the layer model
1972 RegionList copy = regions;
1974 /* sort according to the model */
1976 if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
1977 RegionSortByLastLayerOp cmp;
1981 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1983 /* find the lowest layer that this region can go on */
1984 size_t j = layers.size();
1986 /* try layer j - 1; it can go on if it overlaps no other region
1987 that is already on that layer
1989 RegionList::iterator k = layers[j - 1].begin();
1990 while (k != layers[j - 1].end()) {
1991 if ((*k)->overlap_equivalent (*i)) {
1997 if (k != layers[j - 1].end()) {
1998 /* no overlap, so we can use this layer */
2005 if (j == layers.size()) {
2006 /* we need a new layer for this region */
2007 layers.push_back (RegionList ());
2010 layers[j].push_back (*i);
2013 /* first pass: set up the layer numbers in the regions */
2014 for (size_t j = 0; j < layers.size(); ++j) {
2015 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
2016 (*i)->set_layer (j);
2020 /* sending Modified means that various kinds of layering
2021 models operate correctly at the GUI
2022 level. slightly inefficient, but only slightly.
2024 We force a Modified signal here in case no layers actually
2033 /* XXX these layer functions are all deprecated */
2036 Playlist::raise_region (boost::shared_ptr<Region> region)
2038 uint32_t rsz = regions.size();
2039 layer_t target = region->layer() + 1U;
2041 if (target >= rsz) {
2042 /* its already at the effective top */
2046 move_region_to_layer (target, region, 1);
2050 Playlist::lower_region (boost::shared_ptr<Region> region)
2052 if (region->layer() == 0) {
2053 /* its already at the bottom */
2057 layer_t target = region->layer() - 1U;
2059 move_region_to_layer (target, region, -1);
2063 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2065 /* does nothing useful if layering mode is later=higher */
2066 if ((Config->get_layer_model() == MoveAddHigher) ||
2067 (Config->get_layer_model() == AddHigher)) {
2068 timestamp_layer_op (region);
2074 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2076 /* does nothing useful if layering mode is later=higher */
2077 if ((Config->get_layer_model() == MoveAddHigher) ||
2078 (Config->get_layer_model() == AddHigher)) {
2079 region->set_last_layer_op (0);
2085 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2087 RegionList::iterator i;
2088 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2089 list<LayerInfo> layerinfo;
2093 RegionLock rlock (const_cast<Playlist *> (this));
2095 for (i = regions.begin(); i != regions.end(); ++i) {
2103 /* region is moving up, move all regions on intermediate layers
2107 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2108 dest = (*i)->layer() - 1;
2115 /* region is moving down, move all regions on intermediate layers
2119 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2120 dest = (*i)->layer() + 1;
2130 newpair.second = dest;
2132 layerinfo.push_back (newpair);
2136 /* now reset the layers without holding the region lock */
2138 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2139 x->first->set_layer (x->second);
2142 region->set_layer (target_layer);
2145 /* now check all dependents */
2147 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2148 check_dependents (x->first, false);
2151 check_dependents (region, false);
2158 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2160 RegionList::iterator i;
2167 RegionLock rlock (const_cast<Playlist *> (this));
2169 for (i = regions.begin(); i != regions.end(); ++i) {
2171 if ((*i)->position() >= start) {
2175 if ((*i)->last_frame() > max_frames - distance) {
2176 new_pos = max_frames - (*i)->length();
2178 new_pos = (*i)->position() + distance;
2183 if ((*i)->position() > distance) {
2184 new_pos = (*i)->position() - distance;
2190 (*i)->set_position (new_pos, this);
2198 notify_length_changed ();
2203 boost::shared_ptr<Region>
2204 Playlist::find_region (const ID& id) const
2206 RegionLock rlock (const_cast<Playlist*> (this));
2208 /* searches all regions currently in use by the playlist */
2210 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2211 if ((*i)->id() == id) {
2216 return boost::shared_ptr<Region> ();
2219 boost::shared_ptr<Region>
2220 Playlist::region_by_id (ID id)
2222 /* searches all regions ever added to this playlist */
2224 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2225 if ((*i)->id() == id) {
2229 return boost::shared_ptr<Region> ();
2233 Playlist::dump () const
2235 boost::shared_ptr<Region> r;
2237 cerr << "Playlist \"" << _name << "\" " << endl
2238 << regions.size() << " regions "
2241 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2243 cerr << " " << r->name() << " ["
2244 << r->start() << "+" << r->length()
2254 Playlist::set_frozen (bool yn)
2260 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2262 // struct timeval tv;
2263 // gettimeofday (&tv, 0);
2264 region->set_last_layer_op (++layer_op_counter);
2269 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2274 if (region->locked()) {
2281 RegionLock rlock (const_cast<Playlist*> (this));
2286 RegionList::iterator next;
2288 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2289 if ((*i) == region) {
2293 if (next != regions.end()) {
2295 if ((*next)->locked()) {
2299 if ((*next)->position() != region->last_frame() + 1) {
2300 /* they didn't used to touch, so after shuffle,
2301 just have them swap positions.
2303 new_pos = (*next)->position();
2305 /* they used to touch, so after shuffle,
2306 make sure they still do. put the earlier
2307 region where the later one will end after
2310 new_pos = region->position() + (*next)->length();
2313 (*next)->set_position (region->position(), this);
2314 region->set_position (new_pos, this);
2316 /* avoid a full sort */
2318 regions.erase (i); // removes the region from the list */
2320 regions.insert (next, region); // adds it back after next
2329 RegionList::iterator prev = regions.end();
2331 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2332 if ((*i) == region) {
2334 if (prev != regions.end()) {
2336 if ((*prev)->locked()) {
2340 if (region->position() != (*prev)->last_frame() + 1) {
2341 /* they didn't used to touch, so after shuffle,
2342 just have them swap positions.
2344 new_pos = region->position();
2346 /* they used to touch, so after shuffle,
2347 make sure they still do. put the earlier
2348 one where the later one will end after
2350 new_pos = (*prev)->position() + region->length();
2353 region->set_position ((*prev)->position(), this);
2354 (*prev)->set_position (new_pos, this);
2356 /* avoid a full sort */
2358 regions.erase (i); // remove region
2359 regions.insert (prev, region); // insert region before prev
2375 check_dependents (region, false);
2383 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2385 RegionLock rlock (const_cast<Playlist*> (this));
2387 if (regions.size() > 1) {
2395 Playlist::update_after_tempo_map_change ()
2397 RegionLock rlock (const_cast<Playlist*> (this));
2398 RegionList copy (regions);
2402 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2403 (*i)->update_position_after_tempo_map_change ();