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 times = fabs (times);
472 int itimes = (int) floor (times);
474 nframes_t pos = position;
477 add_region_internal (region, pos);
478 pos += region->length();
483 /* note that itimes can be zero if we being asked to just
484 insert a single fraction of the region.
487 for (int i = 0; i < itimes; ++i) {
488 boost::shared_ptr<Region> copy = RegionFactory::create (region);
489 add_region_internal (copy, pos);
490 pos += region->length();
493 nframes_t length = 0;
495 if (floor (times) != times) {
496 length = (nframes_t) floor (region->length() * (times - floor (times)));
498 _session.region_name (name, region->name(), false);
499 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
500 add_region_internal (sub, pos);
504 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
508 Playlist::set_region_ownership ()
510 RegionLock rl (this);
511 RegionList::iterator i;
512 boost::weak_ptr<Playlist> pl (shared_from_this());
514 for (i = regions.begin(); i != regions.end(); ++i) {
515 (*i)->set_playlist (pl);
520 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
522 if (region->data_type() != _type)
525 RegionSortByPosition cmp;
526 nframes_t old_length = 0;
528 if (!holding_state()) {
529 old_length = _get_maximum_extent();
532 if (!first_set_state) {
533 boost::shared_ptr<Playlist> foo (shared_from_this());
534 region->set_playlist (boost::weak_ptr<Playlist>(foo));
537 region->set_position (position, this);
539 timestamp_layer_op (region);
541 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
542 all_regions.insert (region);
544 possibly_splice_unlocked (position, region->length(), region);
546 if (!holding_state () && !in_set_state) {
547 /* layers get assigned from XML state */
551 /* we need to notify the existence of new region before checking dependents. Ick. */
553 notify_region_added (region);
555 if (!holding_state ()) {
556 check_dependents (region, false);
557 if (old_length != _get_maximum_extent()) {
558 notify_length_changed ();
562 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
563 boost::weak_ptr<Region> (region)));
569 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
571 RegionLock rlock (this);
573 bool old_sp = _splicing;
576 remove_region_internal (old);
577 add_region_internal (newr, pos);
581 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
585 Playlist::remove_region (boost::shared_ptr<Region> region)
587 RegionLock rlock (this);
588 remove_region_internal (region);
592 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
594 RegionList::iterator i;
595 nframes_t old_length = 0;
597 if (!holding_state()) {
598 old_length = _get_maximum_extent();
603 region->set_playlist (boost::weak_ptr<Playlist>());
606 for (i = regions.begin(); i != regions.end(); ++i) {
609 nframes_t pos = (*i)->position();
610 nframes64_t distance = (*i)->length();
614 possibly_splice_unlocked (pos, -distance);
616 if (!holding_state ()) {
618 remove_dependents (region);
620 if (old_length != _get_maximum_extent()) {
621 notify_length_changed ();
625 notify_region_removed (region);
636 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
638 if (Config->get_use_overlap_equivalency()) {
639 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
640 if ((*i)->overlap_equivalent (other)) {
641 results.push_back ((*i));
645 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
646 if ((*i)->equivalent (other)) {
647 results.push_back ((*i));
654 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
656 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
658 if ((*i) && (*i)->region_list_equivalent (other)) {
659 results.push_back (*i);
665 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
669 partition_internal (start, end, false, thawlist);
671 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
672 (*i)->thaw ("separation");
677 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
679 RegionList new_regions;
682 RegionLock rlock (this);
683 boost::shared_ptr<Region> region;
684 boost::shared_ptr<Region> current;
686 RegionList::iterator tmp;
688 nframes_t pos1, pos2, pos3, pos4;
692 /* need to work from a copy, because otherwise the regions we add during the process
693 get operated on as well.
696 RegionList copy = regions;
698 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
705 if (current->first_frame() >= start && current->last_frame() < end) {
707 remove_region_internal (current);
712 /* coverage will return OverlapStart if the start coincides
713 with the end point. we do not partition such a region,
714 so catch this special case.
717 if (current->first_frame() >= end) {
721 if ((overlap = current->coverage (start, end)) == OverlapNone) {
725 pos1 = current->position();
728 pos4 = current->last_frame();
730 if (overlap == OverlapInternal) {
732 /* split: we need 3 new regions, the front, middle and end.
733 cut: we need 2 regions, the front and end.
738 ---------------*************************------------
741 ---------------*****++++++++++++++++====------------
743 ---------------*****----------------====------------
749 /* "middle" ++++++ */
751 _session.region_name (new_name, current->name(), false);
752 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
753 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
754 add_region_internal (region, start);
755 new_regions.push_back (region);
760 _session.region_name (new_name, current->name(), false);
761 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
762 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
764 add_region_internal (region, end);
765 new_regions.push_back (region);
770 thawlist.push_back (current);
771 current->trim_end (pos2, this);
773 } else if (overlap == OverlapEnd) {
777 ---------------*************************------------
780 ---------------**************+++++++++++------------
782 ---------------**************-----------------------
789 _session.region_name (new_name, current->name(), false);
790 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
791 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
792 add_region_internal (region, start);
793 new_regions.push_back (region);
799 thawlist.push_back (current);
800 current->trim_end (pos2, this);
802 } else if (overlap == OverlapStart) {
804 /* split: we need 2 regions: the front and the end.
805 cut: just trim current to skip the cut area
810 ---------------*************************------------
814 ---------------****+++++++++++++++++++++------------
816 -------------------*********************------------
823 _session.region_name (new_name, current->name(), false);
824 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
825 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
826 add_region_internal (region, pos1);
827 new_regions.push_back (region);
833 thawlist.push_back (current);
834 current->trim_front (pos3, this);
836 } else if (overlap == OverlapExternal) {
838 /* split: no split required.
839 cut: remove the region.
844 ---------------*************************------------
848 ---------------*************************------------
850 ----------------------------------------------------
855 remove_region_internal (current);
857 new_regions.push_back (current);
861 in_partition = false;
864 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
865 check_dependents (*i, false);
869 boost::shared_ptr<Playlist>
870 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
872 boost::shared_ptr<Playlist> ret;
873 boost::shared_ptr<Playlist> pl;
876 if (ranges.empty()) {
877 return boost::shared_ptr<Playlist>();
880 start = ranges.front().start;
882 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
884 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
886 if (i == ranges.begin()) {
890 /* paste the next section into the nascent playlist,
891 offset to reflect the start of the first range we
895 ret->paste (pl, (*i).start - start, 1.0f);
902 boost::shared_ptr<Playlist>
903 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
905 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
906 return cut_copy (pmf, ranges, result_is_hidden);
909 boost::shared_ptr<Playlist>
910 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
912 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
913 return cut_copy (pmf, ranges, result_is_hidden);
916 boost::shared_ptr<Playlist>
917 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
919 boost::shared_ptr<Playlist> the_copy;
923 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
924 string new_name = _name;
928 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
929 return boost::shared_ptr<Playlist>();
932 partition_internal (start, start+cnt-1, true, thawlist);
934 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
935 (*i)->thaw ("playlist cut");
941 boost::shared_ptr<Playlist>
942 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
946 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
947 string new_name = _name;
951 cnt = min (_get_maximum_extent() - start, cnt);
952 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
956 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
958 times = fabs (times);
959 nframes_t old_length;
962 RegionLock rl1 (this);
963 RegionLock rl2 (other.get());
965 old_length = _get_maximum_extent();
967 int itimes = (int) floor (times);
968 nframes_t pos = position;
969 nframes_t shift = other->_get_maximum_extent();
970 layer_t top_layer = regions.size();
973 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
974 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
976 /* put these new regions on top of all existing ones, but preserve
977 the ordering they had in the original playlist.
980 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
981 add_region_internal (copy_of_region, copy_of_region->position() + pos);
987 /* XXX shall we handle fractional cases at some point? */
989 if (old_length != _get_maximum_extent()) {
990 notify_length_changed ();
1001 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1003 times = fabs (times);
1005 RegionLock rl (this);
1006 int itimes = (int) floor (times);
1007 nframes_t pos = position;
1010 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1011 add_region_internal (copy, pos);
1012 pos += region->length();
1015 if (floor (times) != times) {
1016 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1018 _session.region_name (name, region->name(), false);
1019 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1020 add_region_internal (sub, pos);
1025 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1027 RegionLock rlock (this);
1028 RegionList copy (regions);
1031 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1033 if ((*r)->last_frame() < at) {
1038 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1039 /* intersected region */
1040 if (!move_intersected) {
1045 /* do not move regions glued to music time - that
1046 has to be done separately.
1049 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1050 fixup.push_back (*r);
1054 (*r)->set_position ((*r)->position() + distance, this);
1057 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1058 (*r)->recompute_position_from_lock_style ();
1063 Playlist::split (nframes64_t at)
1065 RegionLock rlock (this);
1066 RegionList copy (regions);
1068 /* use a copy since this operation can modify the region list
1071 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1072 _split_region (*r, at);
1077 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1079 RegionLock rl (this);
1080 _split_region (region, playlist_position);
1084 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1086 if (!region->covers (playlist_position)) {
1090 if (region->position() == playlist_position ||
1091 region->last_frame() == playlist_position) {
1095 boost::shared_ptr<Region> left;
1096 boost::shared_ptr<Region> right;
1102 /* split doesn't change anything about length, so don't try to splice */
1104 bool old_sp = _splicing;
1107 before = playlist_position - region->position();
1108 after = region->length() - before;
1110 _session.region_name (before_name, region->name(), false);
1111 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1113 _session.region_name (after_name, region->name(), false);
1114 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1116 add_region_internal (left, region->position());
1117 add_region_internal (right, region->position() + before);
1119 uint64_t orig_layer_op = region->last_layer_op();
1120 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1121 if ((*i)->last_layer_op() > orig_layer_op) {
1122 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1126 left->set_last_layer_op ( orig_layer_op );
1127 right->set_last_layer_op ( orig_layer_op + 1);
1131 finalize_split_region (region, left, right);
1133 remove_region_internal (region);
1139 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1141 if (_splicing || in_set_state) {
1142 /* don't respond to splicing moves or state setting */
1146 if (_edit_mode == Splice) {
1147 splice_locked (at, distance, exclude);
1152 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1154 if (_splicing || in_set_state) {
1155 /* don't respond to splicing moves or state setting */
1159 if (_edit_mode == Splice) {
1160 splice_unlocked (at, distance, exclude);
1165 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1168 RegionLock rl (this);
1169 core_splice (at, distance, exclude);
1174 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1176 core_splice (at, distance, exclude);
1180 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1184 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1186 if (exclude && (*i) == exclude) {
1190 if ((*i)->position() >= at) {
1191 nframes64_t new_pos = (*i)->position() + distance;
1194 } else if (new_pos >= max_frames - (*i)->length()) {
1195 new_pos = max_frames - (*i)->length();
1198 (*i)->set_position (new_pos, this);
1204 notify_length_changed ();
1208 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1210 if (in_set_state || _splicing || _nudging || _shuffling) {
1214 if (what_changed & ARDOUR::PositionChanged) {
1216 /* remove it from the list then add it back in
1217 the right place again.
1220 RegionSortByPosition cmp;
1222 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1224 if (i == regions.end()) {
1225 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1226 _name, region->name())
1232 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1235 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1237 nframes64_t delta = 0;
1239 if (what_changed & ARDOUR::PositionChanged) {
1240 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1243 if (what_changed & ARDOUR::LengthChanged) {
1244 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1248 possibly_splice (region->last_position() + region->last_length(), delta, region);
1251 if (holding_state ()) {
1252 pending_bounds.push_back (region);
1254 if (Config->get_layer_model() == MoveAddHigher) {
1255 /* it moved or changed length, so change the timestamp */
1256 timestamp_layer_op (region);
1259 notify_length_changed ();
1261 check_dependents (region, false);
1267 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1269 boost::shared_ptr<Region> region (weak_region.lock());
1276 /* this makes a virtual call to the right kind of playlist ... */
1278 region_changed (what_changed, region);
1282 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1284 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1287 if (in_set_state || in_flush) {
1292 if (what_changed & BoundsChanged) {
1293 region_bounds_changed (what_changed, region);
1294 save = !(_splicing || _nudging);
1297 if ((what_changed & our_interests) &&
1298 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1299 check_dependents (region, false);
1302 if (what_changed & our_interests) {
1311 Playlist::drop_regions ()
1313 RegionLock rl (this);
1315 all_regions.clear ();
1319 Playlist::clear (bool with_signals)
1322 RegionLock rl (this);
1323 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1324 pending_removes.insert (*i);
1330 pending_length = false;
1332 pending_modified = false;
1338 /***********************************************************************
1340 **********************************************************************/
1342 Playlist::RegionList *
1343 Playlist::regions_at (nframes_t frame)
1346 RegionLock rlock (this);
1347 return find_regions_at (frame);
1350 boost::shared_ptr<Region>
1351 Playlist::top_region_at (nframes_t frame)
1354 RegionLock rlock (this);
1355 RegionList *rlist = find_regions_at (frame);
1356 boost::shared_ptr<Region> region;
1358 if (rlist->size()) {
1359 RegionSortByLayer cmp;
1361 region = rlist->back();
1368 Playlist::RegionList*
1369 Playlist::regions_to_read (nframes_t start, nframes_t end)
1371 /* Caller must hold lock */
1373 RegionList covering;
1374 set<nframes_t> to_check;
1375 set<boost::shared_ptr<Region> > unique;
1378 to_check.insert (start);
1379 to_check.insert (end);
1381 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1383 /* find all/any regions that span start+end */
1385 switch ((*i)->coverage (start, end)) {
1389 case OverlapInternal:
1390 covering.push_back (*i);
1394 to_check.insert ((*i)->position());
1395 covering.push_back (*i);
1399 to_check.insert ((*i)->last_frame());
1400 covering.push_back (*i);
1403 case OverlapExternal:
1404 covering.push_back (*i);
1405 to_check.insert ((*i)->position());
1406 to_check.insert ((*i)->last_frame());
1410 /* don't go too far */
1412 if ((*i)->position() > end) {
1417 RegionList* rlist = new RegionList;
1419 /* find all the regions that cover each position .... */
1421 if (covering.size() == 1) {
1423 rlist->push_back (covering.front());
1427 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1431 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1433 if ((*x)->covers (*t)) {
1434 here.push_back (*x);
1438 RegionSortByLayer cmp;
1441 /* ... and get the top/transparent regions at "here" */
1443 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1447 if ((*c)->opaque()) {
1449 /* the other regions at this position are hidden by this one */
1456 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1457 rlist->push_back (*s);
1460 if (rlist->size() > 1) {
1461 /* now sort by time order */
1463 RegionSortByPosition cmp;
1471 Playlist::RegionList *
1472 Playlist::find_regions_at (nframes_t frame)
1474 /* Caller must hold lock */
1476 RegionList *rlist = new RegionList;
1478 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1479 if ((*i)->covers (frame)) {
1480 rlist->push_back (*i);
1487 Playlist::RegionList *
1488 Playlist::regions_touched (nframes_t start, nframes_t end)
1490 RegionLock rlock (this);
1491 RegionList *rlist = new RegionList;
1493 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1494 if ((*i)->coverage (start, end) != OverlapNone) {
1495 rlist->push_back (*i);
1503 Playlist::find_next_transient (nframes64_t from, int dir)
1505 RegionLock rlock (this);
1506 AnalysisFeatureList points;
1507 AnalysisFeatureList these_points;
1509 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1511 if ((*i)->last_frame() < from) {
1515 if ((*i)->first_frame() > from) {
1520 (*i)->get_transients (these_points);
1522 /* add first frame, just, err, because */
1524 these_points.push_back ((*i)->first_frame());
1526 points.insert (points.end(), these_points.begin(), these_points.end());
1527 these_points.clear ();
1530 if (points.empty()) {
1534 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1535 bool reached = false;
1538 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1543 if (reached && (*x) > from) {
1548 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1553 if (reached && (*x) < from) {
1562 boost::shared_ptr<Region>
1563 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1565 RegionLock rlock (this);
1566 boost::shared_ptr<Region> ret;
1567 nframes_t closest = max_frames;
1570 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1573 boost::shared_ptr<Region> r = (*i);
1578 pos = r->first_frame ();
1581 pos = r->last_frame ();
1584 pos = r->adjust_to_sync (r->first_frame());
1589 case 1: /* forwards */
1592 if ((distance = pos - frame) < closest) {
1600 default: /* backwards */
1603 if ((distance = frame - pos) < closest) {
1616 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1618 RegionLock rlock (this);
1620 nframes64_t closest = max_frames;
1621 nframes64_t ret = -1;
1625 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1627 boost::shared_ptr<Region> r = (*i);
1628 nframes64_t distance;
1629 nframes64_t end = r->position() + r->length();
1634 if (r->first_frame() > frame) {
1636 distance = r->first_frame() - frame;
1638 if (distance < closest) {
1639 ret = r->first_frame();
1647 distance = end - frame;
1649 if (distance < closest) {
1663 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1665 boost::shared_ptr<Region> r = (*i);
1666 nframes64_t distance;
1671 if (r->last_frame() < frame) {
1673 distance = frame - r->last_frame();
1675 if (distance < closest) {
1676 ret = r->last_frame();
1682 if (r->first_frame() < frame) {
1683 distance = frame - r->last_frame();
1685 if (distance < closest) {
1686 ret = r->first_frame();
1701 /***********************************************************************/
1706 Playlist::mark_session_dirty ()
1708 if (!in_set_state && !holding_state ()) {
1709 _session.set_dirty();
1714 Playlist::set_state (const XMLNode& node)
1718 XMLNodeConstIterator niter;
1719 XMLPropertyList plist;
1720 XMLPropertyConstIterator piter;
1722 boost::shared_ptr<Region> region;
1727 if (node.name() != "Playlist") {
1734 plist = node.properties();
1736 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1740 if (prop->name() == X_("name")) {
1741 _name = prop->value();
1742 } else if (prop->name() == X_("orig_diskstream_id")) {
1743 _orig_diskstream_id = prop->value ();
1744 } else if (prop->name() == X_("frozen")) {
1745 _frozen = (prop->value() == X_("yes"));
1751 nlist = node.children();
1753 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1757 if (child->name() == "Region") {
1759 if ((prop = child->property ("id")) == 0) {
1760 error << _("region state node has no ID, ignored") << endmsg;
1764 ID id = prop->value ();
1766 if ((region = region_by_id (id))) {
1768 Change what_changed = Change (0);
1770 if (region->set_live_state (*child, what_changed, true)) {
1771 error << _("Playlist: cannot reset region state from XML") << endmsg;
1775 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1776 error << _("Playlist: cannot create region from XML") << endmsg;
1780 add_region (region, region->position(), 1.0);
1782 // So that layer_op ordering doesn't get screwed up
1783 region->set_last_layer_op( region->layer());
1792 /* update dependents, which was not done during add_region_internal
1793 due to in_set_state being true
1796 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1797 check_dependents (*r, false);
1801 first_set_state = false;
1806 Playlist::get_state()
1812 Playlist::get_template()
1814 return state(false);
1818 Playlist::state (bool full_state)
1820 XMLNode *node = new XMLNode (X_("Playlist"));
1823 node->add_property (X_("name"), _name);
1824 node->add_property (X_("type"), _type.to_string());
1826 _orig_diskstream_id.print (buf, sizeof (buf));
1827 node->add_property (X_("orig_diskstream_id"), buf);
1828 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1831 RegionLock rlock (this, false);
1832 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1833 node->add_child_nocopy ((*i)->get_state());
1838 node->add_child_copy (*_extra_xml);
1845 Playlist::empty() const
1847 RegionLock rlock (const_cast<Playlist *>(this), false);
1848 return regions.empty();
1852 Playlist::n_regions() const
1854 RegionLock rlock (const_cast<Playlist *>(this), false);
1855 return regions.size();
1859 Playlist::get_maximum_extent () const
1861 RegionLock rlock (const_cast<Playlist *>(this), false);
1862 return _get_maximum_extent ();
1866 Playlist::_get_maximum_extent () const
1868 RegionList::const_iterator i;
1869 nframes_t max_extent = 0;
1872 for (i = regions.begin(); i != regions.end(); ++i) {
1873 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1882 Playlist::bump_name (string name, Session &session)
1884 string newname = name;
1887 newname = bump_name_once (newname);
1888 } while (session.playlist_by_name (newname)!=NULL);
1895 Playlist::top_layer() const
1897 RegionLock rlock (const_cast<Playlist *> (this));
1900 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1901 top = max (top, (*i)->layer());
1907 Playlist::set_edit_mode (EditMode mode)
1912 /********************
1914 ********************/
1917 Playlist::relayer ()
1919 /* don't send multiple Modified notifications
1920 when multiple regions are relayered.
1925 /* build up a new list of regions on each layer */
1927 std::vector<RegionList> layers;
1929 /* we want to go through regions from desired lowest to desired highest layer,
1930 which depends on the layer model
1933 RegionList copy = regions;
1935 /* sort according to the model */
1937 if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
1938 RegionSortByLastLayerOp cmp;
1942 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1944 /* find the lowest layer that this region can go on */
1945 size_t j = layers.size();
1947 /* try layer j - 1; it can go on if it overlaps no other region
1948 that is already on that layer
1950 RegionList::iterator k = layers[j - 1].begin();
1951 while (k != layers[j - 1].end()) {
1952 if ((*k)->overlap_equivalent (*i)) {
1958 if (k != layers[j - 1].end()) {
1959 /* no overlap, so we can use this layer */
1966 if (j == layers.size()) {
1967 /* we need a new layer for this region */
1968 layers.push_back (RegionList ());
1971 layers[j].push_back (*i);
1974 /* first pass: set up the layer numbers in the regions */
1975 for (size_t j = 0; j < layers.size(); ++j) {
1976 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
1977 (*i)->set_layer (j);
1981 /* sending Modified means that various kinds of layering
1982 models operate correctly at the GUI
1983 level. slightly inefficient, but only slightly.
1985 We force a Modified signal here in case no layers actually
1994 /* XXX these layer functions are all deprecated */
1997 Playlist::raise_region (boost::shared_ptr<Region> region)
1999 uint32_t rsz = regions.size();
2000 layer_t target = region->layer() + 1U;
2002 if (target >= rsz) {
2003 /* its already at the effective top */
2007 move_region_to_layer (target, region, 1);
2011 Playlist::lower_region (boost::shared_ptr<Region> region)
2013 if (region->layer() == 0) {
2014 /* its already at the bottom */
2018 layer_t target = region->layer() - 1U;
2020 move_region_to_layer (target, region, -1);
2024 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2026 /* does nothing useful if layering mode is later=higher */
2027 if ((Config->get_layer_model() == MoveAddHigher) ||
2028 (Config->get_layer_model() == AddHigher)) {
2029 timestamp_layer_op (region);
2035 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2037 /* does nothing useful if layering mode is later=higher */
2038 if ((Config->get_layer_model() == MoveAddHigher) ||
2039 (Config->get_layer_model() == AddHigher)) {
2040 region->set_last_layer_op (0);
2046 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2048 RegionList::iterator i;
2049 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2050 list<LayerInfo> layerinfo;
2054 RegionLock rlock (const_cast<Playlist *> (this));
2056 for (i = regions.begin(); i != regions.end(); ++i) {
2064 /* region is moving up, move all regions on intermediate layers
2068 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2069 dest = (*i)->layer() - 1;
2076 /* region is moving down, move all regions on intermediate layers
2080 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2081 dest = (*i)->layer() + 1;
2091 newpair.second = dest;
2093 layerinfo.push_back (newpair);
2097 /* now reset the layers without holding the region lock */
2099 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2100 x->first->set_layer (x->second);
2103 region->set_layer (target_layer);
2106 /* now check all dependents */
2108 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2109 check_dependents (x->first, false);
2112 check_dependents (region, false);
2119 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2121 RegionList::iterator i;
2128 RegionLock rlock (const_cast<Playlist *> (this));
2130 for (i = regions.begin(); i != regions.end(); ++i) {
2132 if ((*i)->position() >= start) {
2136 if ((*i)->last_frame() > max_frames - distance) {
2137 new_pos = max_frames - (*i)->length();
2139 new_pos = (*i)->position() + distance;
2144 if ((*i)->position() > distance) {
2145 new_pos = (*i)->position() - distance;
2151 (*i)->set_position (new_pos, this);
2159 notify_length_changed ();
2164 boost::shared_ptr<Region>
2165 Playlist::find_region (const ID& id) const
2167 RegionLock rlock (const_cast<Playlist*> (this));
2169 /* searches all regions currently in use by the playlist */
2171 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2172 if ((*i)->id() == id) {
2177 return boost::shared_ptr<Region> ();
2180 boost::shared_ptr<Region>
2181 Playlist::region_by_id (ID id)
2183 /* searches all regions ever added to this playlist */
2185 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2186 if ((*i)->id() == id) {
2190 return boost::shared_ptr<Region> ();
2194 Playlist::dump () const
2196 boost::shared_ptr<Region> r;
2198 cerr << "Playlist \"" << _name << "\" " << endl
2199 << regions.size() << " regions "
2202 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2204 cerr << " " << r->name() << " ["
2205 << r->start() << "+" << r->length()
2215 Playlist::set_frozen (bool yn)
2221 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2223 // struct timeval tv;
2224 // gettimeofday (&tv, 0);
2225 region->set_last_layer_op (++layer_op_counter);
2230 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2235 if (region->locked()) {
2242 RegionLock rlock (const_cast<Playlist*> (this));
2247 RegionList::iterator next;
2249 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2250 if ((*i) == region) {
2254 if (next != regions.end()) {
2256 if ((*next)->locked()) {
2260 if ((*next)->position() != region->last_frame() + 1) {
2261 /* they didn't used to touch, so after shuffle,
2262 just have them swap positions.
2264 new_pos = (*next)->position();
2266 /* they used to touch, so after shuffle,
2267 make sure they still do. put the earlier
2268 region where the later one will end after
2271 new_pos = region->position() + (*next)->length();
2274 (*next)->set_position (region->position(), this);
2275 region->set_position (new_pos, this);
2277 /* avoid a full sort */
2279 regions.erase (i); // removes the region from the list */
2281 regions.insert (next, region); // adds it back after next
2290 RegionList::iterator prev = regions.end();
2292 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2293 if ((*i) == region) {
2295 if (prev != regions.end()) {
2297 if ((*prev)->locked()) {
2301 if (region->position() != (*prev)->last_frame() + 1) {
2302 /* they didn't used to touch, so after shuffle,
2303 just have them swap positions.
2305 new_pos = region->position();
2307 /* they used to touch, so after shuffle,
2308 make sure they still do. put the earlier
2309 one where the later one will end after
2311 new_pos = (*prev)->position() + region->length();
2314 region->set_position ((*prev)->position(), this);
2315 (*prev)->set_position (new_pos, this);
2317 /* avoid a full sort */
2319 regions.erase (i); // remove region
2320 regions.insert (prev, region); // insert region before prev
2336 check_dependents (region, false);
2344 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2346 RegionLock rlock (const_cast<Playlist*> (this));
2348 if (regions.size() > 1) {
2356 Playlist::update_after_tempo_map_change ()
2358 RegionLock rlock (const_cast<Playlist*> (this));
2359 RegionList copy (regions);
2363 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2364 (*i)->update_position_after_tempo_map_change ();