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;
1669 if (r->first_frame() > frame) {
1671 distance = r->first_frame() - frame;
1673 if (distance < closest) {
1674 ret = r->first_frame();
1679 if (r->last_frame () > frame) {
1681 distance = r->last_frame () - frame;
1683 if (distance < closest) {
1684 ret = r->last_frame ();
1692 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1694 boost::shared_ptr<Region> r = (*i);
1695 nframes64_t distance;
1697 if (r->last_frame() < frame) {
1699 distance = frame - r->last_frame();
1701 if (distance < closest) {
1702 ret = r->last_frame();
1707 if (r->first_frame() < frame) {
1709 distance = frame - r->first_frame();
1711 if (distance < closest) {
1712 ret = r->first_frame();
1722 /***********************************************************************/
1727 Playlist::mark_session_dirty ()
1729 if (!in_set_state && !holding_state ()) {
1730 _session.set_dirty();
1735 Playlist::set_state (const XMLNode& node)
1739 XMLNodeConstIterator niter;
1740 XMLPropertyList plist;
1741 XMLPropertyConstIterator piter;
1743 boost::shared_ptr<Region> region;
1748 if (node.name() != "Playlist") {
1755 plist = node.properties();
1757 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1761 if (prop->name() == X_("name")) {
1762 _name = prop->value();
1763 } else if (prop->name() == X_("orig_diskstream_id")) {
1764 _orig_diskstream_id = prop->value ();
1765 } else if (prop->name() == X_("frozen")) {
1766 _frozen = (prop->value() == X_("yes"));
1772 nlist = node.children();
1774 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1778 if (child->name() == "Region") {
1780 if ((prop = child->property ("id")) == 0) {
1781 error << _("region state node has no ID, ignored") << endmsg;
1785 ID id = prop->value ();
1787 if ((region = region_by_id (id))) {
1789 Change what_changed = Change (0);
1791 if (region->set_live_state (*child, what_changed, true)) {
1792 error << _("Playlist: cannot reset region state from XML") << endmsg;
1796 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1797 error << _("Playlist: cannot create region from XML") << endmsg;
1801 add_region (region, region->position(), 1.0);
1803 // So that layer_op ordering doesn't get screwed up
1804 region->set_last_layer_op( region->layer());
1813 /* update dependents, which was not done during add_region_internal
1814 due to in_set_state being true
1817 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1818 check_dependents (*r, false);
1822 first_set_state = false;
1827 Playlist::get_state()
1833 Playlist::get_template()
1835 return state(false);
1839 Playlist::state (bool full_state)
1841 XMLNode *node = new XMLNode (X_("Playlist"));
1844 node->add_property (X_("name"), _name);
1845 node->add_property (X_("type"), _type.to_string());
1847 _orig_diskstream_id.print (buf, sizeof (buf));
1848 node->add_property (X_("orig_diskstream_id"), buf);
1849 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1852 RegionLock rlock (this, false);
1853 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1854 node->add_child_nocopy ((*i)->get_state());
1859 node->add_child_copy (*_extra_xml);
1866 Playlist::empty() const
1868 RegionLock rlock (const_cast<Playlist *>(this), false);
1869 return regions.empty();
1873 Playlist::n_regions() const
1875 RegionLock rlock (const_cast<Playlist *>(this), false);
1876 return regions.size();
1880 Playlist::get_maximum_extent () const
1882 RegionLock rlock (const_cast<Playlist *>(this), false);
1883 return _get_maximum_extent ();
1887 Playlist::_get_maximum_extent () const
1889 RegionList::const_iterator i;
1890 nframes_t max_extent = 0;
1893 for (i = regions.begin(); i != regions.end(); ++i) {
1894 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1903 Playlist::bump_name (string name, Session &session)
1905 string newname = name;
1908 newname = bump_name_once (newname);
1909 } while (session.playlist_by_name (newname)!=NULL);
1916 Playlist::top_layer() const
1918 RegionLock rlock (const_cast<Playlist *> (this));
1921 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1922 top = max (top, (*i)->layer());
1928 Playlist::set_edit_mode (EditMode mode)
1933 /********************
1935 ********************/
1938 Playlist::relayer ()
1940 /* don't send multiple Modified notifications
1941 when multiple regions are relayered.
1946 /* build up a new list of regions on each layer */
1948 std::vector<RegionList> layers;
1950 /* we want to go through regions from desired lowest to desired highest layer,
1951 which depends on the layer model
1954 RegionList copy = regions;
1956 /* sort according to the model */
1958 if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
1959 RegionSortByLastLayerOp cmp;
1963 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1965 /* find the lowest layer that this region can go on */
1966 size_t j = layers.size();
1968 /* try layer j - 1; it can go on if it overlaps no other region
1969 that is already on that layer
1971 RegionList::iterator k = layers[j - 1].begin();
1972 while (k != layers[j - 1].end()) {
1973 if ((*k)->overlap_equivalent (*i)) {
1979 if (k != layers[j - 1].end()) {
1980 /* no overlap, so we can use this layer */
1987 if (j == layers.size()) {
1988 /* we need a new layer for this region */
1989 layers.push_back (RegionList ());
1992 layers[j].push_back (*i);
1995 /* first pass: set up the layer numbers in the regions */
1996 for (size_t j = 0; j < layers.size(); ++j) {
1997 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
1998 (*i)->set_layer (j);
2002 /* sending Modified means that various kinds of layering
2003 models operate correctly at the GUI
2004 level. slightly inefficient, but only slightly.
2006 We force a Modified signal here in case no layers actually
2015 /* XXX these layer functions are all deprecated */
2018 Playlist::raise_region (boost::shared_ptr<Region> region)
2020 uint32_t rsz = regions.size();
2021 layer_t target = region->layer() + 1U;
2023 if (target >= rsz) {
2024 /* its already at the effective top */
2028 move_region_to_layer (target, region, 1);
2032 Playlist::lower_region (boost::shared_ptr<Region> region)
2034 if (region->layer() == 0) {
2035 /* its already at the bottom */
2039 layer_t target = region->layer() - 1U;
2041 move_region_to_layer (target, region, -1);
2045 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2047 /* does nothing useful if layering mode is later=higher */
2048 if ((Config->get_layer_model() == MoveAddHigher) ||
2049 (Config->get_layer_model() == AddHigher)) {
2050 timestamp_layer_op (region);
2056 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2058 /* does nothing useful if layering mode is later=higher */
2059 if ((Config->get_layer_model() == MoveAddHigher) ||
2060 (Config->get_layer_model() == AddHigher)) {
2061 region->set_last_layer_op (0);
2067 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2069 RegionList::iterator i;
2070 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2071 list<LayerInfo> layerinfo;
2075 RegionLock rlock (const_cast<Playlist *> (this));
2077 for (i = regions.begin(); i != regions.end(); ++i) {
2085 /* region is moving up, move all regions on intermediate layers
2089 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2090 dest = (*i)->layer() - 1;
2097 /* region is moving down, move all regions on intermediate layers
2101 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2102 dest = (*i)->layer() + 1;
2112 newpair.second = dest;
2114 layerinfo.push_back (newpair);
2118 /* now reset the layers without holding the region lock */
2120 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2121 x->first->set_layer (x->second);
2124 region->set_layer (target_layer);
2127 /* now check all dependents */
2129 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2130 check_dependents (x->first, false);
2133 check_dependents (region, false);
2140 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2142 RegionList::iterator i;
2149 RegionLock rlock (const_cast<Playlist *> (this));
2151 for (i = regions.begin(); i != regions.end(); ++i) {
2153 if ((*i)->position() >= start) {
2157 if ((*i)->last_frame() > max_frames - distance) {
2158 new_pos = max_frames - (*i)->length();
2160 new_pos = (*i)->position() + distance;
2165 if ((*i)->position() > distance) {
2166 new_pos = (*i)->position() - distance;
2172 (*i)->set_position (new_pos, this);
2180 notify_length_changed ();
2185 boost::shared_ptr<Region>
2186 Playlist::find_region (const ID& id) const
2188 RegionLock rlock (const_cast<Playlist*> (this));
2190 /* searches all regions currently in use by the playlist */
2192 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2193 if ((*i)->id() == id) {
2198 return boost::shared_ptr<Region> ();
2201 boost::shared_ptr<Region>
2202 Playlist::region_by_id (ID id)
2204 /* searches all regions ever added to this playlist */
2206 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2207 if ((*i)->id() == id) {
2211 return boost::shared_ptr<Region> ();
2215 Playlist::dump () const
2217 boost::shared_ptr<Region> r;
2219 cerr << "Playlist \"" << _name << "\" " << endl
2220 << regions.size() << " regions "
2223 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2225 cerr << " " << r->name() << " ["
2226 << r->start() << "+" << r->length()
2236 Playlist::set_frozen (bool yn)
2242 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2244 // struct timeval tv;
2245 // gettimeofday (&tv, 0);
2246 region->set_last_layer_op (++layer_op_counter);
2251 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2256 if (region->locked()) {
2263 RegionLock rlock (const_cast<Playlist*> (this));
2268 RegionList::iterator next;
2270 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2271 if ((*i) == region) {
2275 if (next != regions.end()) {
2277 if ((*next)->locked()) {
2281 if ((*next)->position() != region->last_frame() + 1) {
2282 /* they didn't used to touch, so after shuffle,
2283 just have them swap positions.
2285 new_pos = (*next)->position();
2287 /* they used to touch, so after shuffle,
2288 make sure they still do. put the earlier
2289 region where the later one will end after
2292 new_pos = region->position() + (*next)->length();
2295 (*next)->set_position (region->position(), this);
2296 region->set_position (new_pos, this);
2298 /* avoid a full sort */
2300 regions.erase (i); // removes the region from the list */
2302 regions.insert (next, region); // adds it back after next
2311 RegionList::iterator prev = regions.end();
2313 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2314 if ((*i) == region) {
2316 if (prev != regions.end()) {
2318 if ((*prev)->locked()) {
2322 if (region->position() != (*prev)->last_frame() + 1) {
2323 /* they didn't used to touch, so after shuffle,
2324 just have them swap positions.
2326 new_pos = region->position();
2328 /* they used to touch, so after shuffle,
2329 make sure they still do. put the earlier
2330 one where the later one will end after
2332 new_pos = (*prev)->position() + region->length();
2335 region->set_position ((*prev)->position(), this);
2336 (*prev)->set_position (new_pos, this);
2338 /* avoid a full sort */
2340 regions.erase (i); // remove region
2341 regions.insert (prev, region); // insert region before prev
2357 check_dependents (region, false);
2365 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2367 RegionLock rlock (const_cast<Playlist*> (this));
2369 if (regions.size() > 1) {
2377 Playlist::update_after_tempo_map_change ()
2379 RegionLock rlock (const_cast<Playlist*> (this));
2380 RegionList copy (regions);
2384 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2385 (*i)->update_position_after_tempo_map_change ();