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>
42 #include <boost/lexical_cast.hpp>
47 using namespace ARDOUR;
50 struct ShowMeTheList {
51 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
53 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
55 boost::shared_ptr<Playlist> playlist;
59 struct RegionSortByLayer {
60 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
61 return a->layer() < b->layer();
65 struct RegionSortByPosition {
66 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
67 return a->position() < b->position();
71 struct RegionSortByLastLayerOp {
72 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
73 return a->last_layer_op() < b->last_layer_op();
77 Playlist::Playlist (Session& sess, string nom, bool hide)
81 first_set_state = false;
86 Playlist::Playlist (Session& sess, const XMLNode& node, bool hide)
90 _name = "unnamed"; /* reset by set_state */
93 /* set state called by derived class */
96 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
97 : _name (namestr), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
102 other->copy_regions (tmp);
106 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
107 add_region_internal( (*x), (*x)->position());
112 _splicing = other->_splicing;
113 _nudging = other->_nudging;
114 _edit_mode = other->_edit_mode;
117 first_set_state = false;
119 in_partition = false;
121 _read_data_count = 0;
122 _frozen = other->_frozen;
124 layer_op_counter = other->layer_op_counter;
125 freeze_length = other->freeze_length;
128 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
129 : _name (str), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
131 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
133 nframes_t end = start + cnt - 1;
139 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
141 boost::shared_ptr<Region> region;
142 boost::shared_ptr<Region> new_region;
143 nframes_t offset = 0;
144 nframes_t position = 0;
151 overlap = region->coverage (start, end);
157 case OverlapInternal:
158 offset = start - region->position();
165 position = region->position() - start;
166 len = end - region->position();
170 offset = start - region->position();
172 len = region->length() - offset;
175 case OverlapExternal:
177 position = region->position() - start;
178 len = region->length();
182 _session.region_name (new_name, region->name(), false);
184 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
186 add_region_internal (new_region, position);
190 first_set_state = false;
192 /* this constructor does NOT notify others (session) */
199 InUse (true); /* EMIT SIGNAL */
210 InUse (false); /* EMIT SIGNAL */
215 Playlist::copy_regions (RegionList& newlist) const
217 RegionLock rlock (const_cast<Playlist *> (this));
219 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
220 newlist.push_back (RegionFactory::RegionFactory::create (*i));
225 Playlist::init (bool hide)
227 g_atomic_int_set (&block_notifications, 0);
228 g_atomic_int_set (&ignore_state_changes, 0);
229 pending_modified = false;
230 pending_length = false;
231 first_set_state = true;
238 _edit_mode = Config->get_edit_mode();
240 in_partition = false;
242 _read_data_count = 0;
244 layer_op_counter = 0;
247 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
250 Playlist::Playlist (const Playlist& pl)
251 : _session (pl._session)
253 fatal << _("playlist const copy constructor called") << endmsg;
256 Playlist::Playlist (Playlist& pl)
257 : _session (pl._session)
259 fatal << _("playlist non-const copy constructor called") << endmsg;
262 Playlist::~Playlist ()
265 RegionLock rl (this);
267 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
268 (*i)->set_playlist (boost::shared_ptr<Playlist>());
272 /* GoingAway must be emitted by derived classes */
276 Playlist::_set_sort_id ()
279 Playlists are given names like <track name>.<id>
280 or <track name>.<edit group name>.<id> where id
281 is an integer. We extract the id and sort by that.
284 size_t dot_position = _name.find_last_of(".");
285 if (dot_position == string::npos)
291 string t = _name.substr(dot_position + 1);
295 _sort_id = boost::lexical_cast<int>(t);
297 catch (boost::bad_lexical_cast e)
305 Playlist::set_name (string str)
307 /* in a typical situation, a playlist is being used
308 by one diskstream and also is referenced by the
309 Session. if there are more references than that,
310 then don't change the name.
323 while (_session.playlist_by_name(name) != 0) {
324 name = bump_name_once(name);
330 NameChanged(); /* EMIT SIGNAL */
333 /***********************************************************************
334 CHANGE NOTIFICATION HANDLING
336 Notifications must be delayed till the region_lock is released. This
337 is necessary because handlers for the signals may need to acquire
338 the lock (e.g. to read from the playlist).
339 ***********************************************************************/
344 delay_notifications ();
345 g_atomic_int_inc (&ignore_state_changes);
351 g_atomic_int_dec_and_test (&ignore_state_changes);
352 release_notifications ();
357 Playlist::delay_notifications ()
359 g_atomic_int_inc (&block_notifications);
360 freeze_length = _get_maximum_extent();
364 Playlist::release_notifications ()
366 if (g_atomic_int_dec_and_test (&block_notifications)) {
367 flush_notifications ();
372 Playlist::notify_modified ()
374 if (holding_state ()) {
375 pending_modified = true;
377 pending_modified = false;
378 Modified(); /* EMIT SIGNAL */
383 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
385 if (holding_state ()) {
386 pending_removes.insert (r);
387 pending_modified = true;
388 pending_length = true;
390 /* this might not be true, but we have to act
391 as though it could be.
393 LengthChanged (); /* EMIT SIGNAL */
394 Modified (); /* EMIT SIGNAL */
399 Playlist::notify_region_added (boost::shared_ptr<Region> r)
401 /* the length change might not be true, but we have to act
402 as though it could be.
405 if (holding_state()) {
406 pending_adds.insert (r);
407 pending_modified = true;
408 pending_length = true;
410 LengthChanged (); /* EMIT SIGNAL */
411 Modified (); /* EMIT SIGNAL */
416 Playlist::notify_length_changed ()
418 if (holding_state ()) {
419 pending_length = true;
421 LengthChanged(); /* EMIT SIGNAL */
422 Modified (); /* EMIT SIGNAL */
427 Playlist::flush_notifications ()
429 set<boost::shared_ptr<Region> > dependent_checks_needed;
430 set<boost::shared_ptr<Region> >::iterator s;
439 /* we have no idea what order the regions ended up in pending
440 bounds (it could be based on selection order, for example).
441 so, to preserve layering in the "most recently moved is higher"
442 model, sort them by existing layer, then timestamp them.
445 // RegionSortByLayer cmp;
446 // pending_bounds.sort (cmp);
448 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
449 if (Config->get_layer_model() == MoveAddHigher) {
450 timestamp_layer_op (*r);
452 pending_length = true;
453 dependent_checks_needed.insert (*r);
457 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
458 dependent_checks_needed.insert (*s);
462 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
463 remove_dependents (*s);
467 if ((freeze_length != _get_maximum_extent()) || pending_length) {
469 LengthChanged(); /* EMIT SIGNAL */
473 if (n || pending_modified) {
477 pending_modified = false;
478 Modified (); /* EMIT SIGNAL */
481 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
482 check_dependents (*s, false);
485 pending_adds.clear ();
486 pending_removes.clear ();
487 pending_bounds.clear ();
492 /*************************************************************
494 *************************************************************/
497 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
499 RegionLock rlock (this);
501 times = fabs (times);
503 int itimes = (int) floor (times);
505 nframes_t pos = position;
508 add_region_internal (region, pos);
509 pos += region->length();
514 /* note that itimes can be zero if we being asked to just
515 insert a single fraction of the region.
518 for (int i = 0; i < itimes; ++i) {
519 boost::shared_ptr<Region> copy = RegionFactory::create (region);
520 add_region_internal (copy, pos);
521 pos += region->length();
524 nframes_t length = 0;
526 if (floor (times) != times) {
527 length = (nframes_t) floor (region->length() * (times - floor (times)));
529 _session.region_name (name, region->name(), false);
530 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
531 add_region_internal (sub, pos);
535 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
539 Playlist::set_region_ownership ()
541 RegionLock rl (this);
542 RegionList::iterator i;
543 boost::weak_ptr<Playlist> pl (shared_from_this());
545 for (i = regions.begin(); i != regions.end(); ++i) {
546 (*i)->set_playlist (pl);
551 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
553 RegionSortByPosition cmp;
554 nframes_t old_length = 0;
556 if (!holding_state()) {
557 old_length = _get_maximum_extent();
560 if (!first_set_state) {
561 boost::shared_ptr<Playlist> foo (shared_from_this());
562 region->set_playlist (boost::weak_ptr<Playlist>(foo));
565 region->set_position (position, this);
567 timestamp_layer_op (region);
569 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
570 all_regions.insert (region);
572 possibly_splice_unlocked (position, region->length(), region);
574 if (!holding_state () && !in_set_state) {
575 /* layers get assigned from XML state */
579 /* we need to notify the existence of new region before checking dependents. Ick. */
581 notify_region_added (region);
583 if (!holding_state ()) {
584 check_dependents (region, false);
585 if (old_length != _get_maximum_extent()) {
586 notify_length_changed ();
590 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
591 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->cut_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->cut_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) {
1318 if (what_changed & BoundsChanged) {
1319 region_bounds_changed (what_changed, region);
1320 save = !(_splicing || _nudging);
1323 if ((what_changed & our_interests) &&
1324 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1325 check_dependents (region, false);
1328 if (what_changed & our_interests) {
1337 Playlist::drop_regions ()
1339 RegionLock rl (this);
1341 all_regions.clear ();
1345 Playlist::clear (bool with_signals)
1348 RegionLock rl (this);
1349 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1350 pending_removes.insert (*i);
1362 /***********************************************************************
1364 **********************************************************************/
1366 Playlist::RegionList *
1367 Playlist::regions_at (nframes_t frame)
1370 RegionLock rlock (this);
1371 return find_regions_at (frame);
1374 boost::shared_ptr<Region>
1375 Playlist::top_region_at (nframes_t frame)
1378 RegionLock rlock (this);
1379 RegionList *rlist = find_regions_at (frame);
1380 boost::shared_ptr<Region> region;
1382 if (rlist->size()) {
1383 RegionSortByLayer cmp;
1385 region = rlist->back();
1392 Playlist::RegionList*
1393 Playlist::regions_to_read (nframes_t start, nframes_t end)
1395 /* Caller must hold lock */
1397 RegionList covering;
1398 set<nframes_t> to_check;
1399 set<boost::shared_ptr<Region> > unique;
1402 to_check.insert (start);
1403 to_check.insert (end);
1405 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1407 /* find all/any regions that span start+end */
1409 switch ((*i)->coverage (start, end)) {
1413 case OverlapInternal:
1414 covering.push_back (*i);
1418 to_check.insert ((*i)->position());
1419 covering.push_back (*i);
1423 to_check.insert ((*i)->last_frame());
1424 covering.push_back (*i);
1427 case OverlapExternal:
1428 covering.push_back (*i);
1429 to_check.insert ((*i)->position());
1430 to_check.insert ((*i)->last_frame());
1434 /* don't go too far */
1436 if ((*i)->position() > end) {
1441 RegionList* rlist = new RegionList;
1443 /* find all the regions that cover each position .... */
1445 if (covering.size() == 1) {
1447 rlist->push_back (covering.front());
1451 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1455 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1457 if ((*x)->covers (*t)) {
1458 here.push_back (*x);
1462 RegionSortByLayer cmp;
1465 /* ... and get the top/transparent regions at "here" */
1467 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1471 if ((*c)->opaque()) {
1473 /* the other regions at this position are hidden by this one */
1480 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1481 rlist->push_back (*s);
1484 if (rlist->size() > 1) {
1485 /* now sort by time order */
1487 RegionSortByPosition cmp;
1495 Playlist::RegionList *
1496 Playlist::find_regions_at (nframes_t frame)
1498 /* Caller must hold lock */
1500 RegionList *rlist = new RegionList;
1502 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1503 if ((*i)->covers (frame)) {
1504 rlist->push_back (*i);
1511 Playlist::RegionList *
1512 Playlist::regions_touched (nframes_t start, nframes_t end)
1514 RegionLock rlock (this);
1515 RegionList *rlist = new RegionList;
1517 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1518 if ((*i)->coverage (start, end) != OverlapNone) {
1519 rlist->push_back (*i);
1527 Playlist::find_next_transient (nframes64_t from, int dir)
1529 RegionLock rlock (this);
1530 AnalysisFeatureList points;
1531 AnalysisFeatureList these_points;
1533 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1535 if ((*i)->last_frame() < from) {
1539 if ((*i)->first_frame() > from) {
1544 (*i)->get_transients (these_points);
1546 /* add first frame, just, err, because */
1548 these_points.push_back ((*i)->first_frame());
1550 points.insert (points.end(), these_points.begin(), these_points.end());
1551 these_points.clear ();
1554 if (points.empty()) {
1558 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1559 bool reached = false;
1562 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1567 if (reached && (*x) > from) {
1572 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1577 if (reached && (*x) < from) {
1586 boost::shared_ptr<Region>
1587 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1589 RegionLock rlock (this);
1590 boost::shared_ptr<Region> ret;
1591 nframes_t closest = max_frames;
1594 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1597 boost::shared_ptr<Region> r = (*i);
1602 pos = r->first_frame ();
1605 pos = r->last_frame ();
1608 pos = r->sync_position ();
1609 // r->adjust_to_sync (r->first_frame());
1614 case 1: /* forwards */
1617 if ((distance = pos - frame) < closest) {
1625 default: /* backwards */
1628 if ((distance = frame - pos) < closest) {
1641 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1643 RegionLock rlock (this);
1645 nframes64_t closest = max_frames;
1646 nframes64_t ret = -1;
1650 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1652 boost::shared_ptr<Region> r = (*i);
1653 nframes64_t distance;
1654 nframes64_t end = r->position() + r->length();
1659 if (r->first_frame() > frame) {
1661 distance = r->first_frame() - frame;
1663 if (distance < closest) {
1664 ret = r->first_frame();
1672 distance = end - frame;
1674 if (distance < closest) {
1688 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1690 boost::shared_ptr<Region> r = (*i);
1691 nframes64_t distance;
1696 if (r->last_frame() < frame) {
1698 distance = frame - r->last_frame();
1700 if (distance < closest) {
1701 ret = r->last_frame();
1707 if (r->first_frame() < frame) {
1708 distance = frame - r->last_frame();
1710 if (distance < closest) {
1711 ret = r->first_frame();
1726 /***********************************************************************/
1731 Playlist::mark_session_dirty ()
1733 if (!in_set_state && !holding_state ()) {
1734 _session.set_dirty();
1739 Playlist::set_state (const XMLNode& node)
1743 XMLNodeConstIterator niter;
1744 XMLPropertyList plist;
1745 XMLPropertyConstIterator piter;
1747 boost::shared_ptr<Region> region;
1752 if (node.name() != "Playlist") {
1759 plist = node.properties();
1761 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1765 if (prop->name() == X_("name")) {
1766 _name = prop->value();
1768 } else if (prop->name() == X_("orig_diskstream_id")) {
1769 _orig_diskstream_id = prop->value ();
1770 } else if (prop->name() == X_("frozen")) {
1771 _frozen = string_is_affirmative (prop->value());
1777 nlist = node.children();
1779 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1783 if (child->name() == "Region") {
1785 if ((prop = child->property ("id")) == 0) {
1786 error << _("region state node has no ID, ignored") << endmsg;
1790 ID id = prop->value ();
1792 if ((region = region_by_id (id))) {
1794 Change what_changed = Change (0);
1796 if (region->set_live_state (*child, what_changed, true)) {
1797 error << _("Playlist: cannot reset region state from XML") << endmsg;
1801 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1802 error << _("Playlist: cannot create region from XML") << endmsg;
1806 add_region (region, region->position(), 1.0);
1808 // So that layer_op ordering doesn't get screwed up
1809 region->set_last_layer_op( region->layer());
1818 /* update dependents, which was not done during add_region_internal
1819 due to in_set_state being true
1822 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1823 check_dependents (*r, false);
1827 first_set_state = false;
1832 Playlist::get_state()
1838 Playlist::get_template()
1840 return state(false);
1844 Playlist::state (bool full_state)
1846 XMLNode *node = new XMLNode (X_("Playlist"));
1849 node->add_property (X_("name"), _name);
1851 _orig_diskstream_id.print (buf, sizeof (buf));
1852 node->add_property (X_("orig_diskstream_id"), buf);
1853 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1856 RegionLock rlock (this, false);
1857 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1858 node->add_child_nocopy ((*i)->get_state());
1863 node->add_child_copy (*_extra_xml);
1870 Playlist::empty() const
1872 RegionLock rlock (const_cast<Playlist *>(this), false);
1873 return regions.empty();
1877 Playlist::n_regions() const
1879 RegionLock rlock (const_cast<Playlist *>(this), false);
1880 return regions.size();
1884 Playlist::get_maximum_extent () const
1886 RegionLock rlock (const_cast<Playlist *>(this), false);
1887 return _get_maximum_extent ();
1891 Playlist::_get_maximum_extent () const
1893 RegionList::const_iterator i;
1894 nframes_t max_extent = 0;
1897 for (i = regions.begin(); i != regions.end(); ++i) {
1898 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1907 Playlist::bump_name (string name, Session &session)
1909 string newname = name;
1912 newname = bump_name_once (newname);
1913 } while (session.playlist_by_name (newname)!=NULL);
1920 Playlist::top_layer() const
1922 RegionLock rlock (const_cast<Playlist *> (this));
1925 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1926 top = max (top, (*i)->layer());
1932 Playlist::set_edit_mode (EditMode mode)
1937 /********************
1939 ********************/
1942 Playlist::relayer ()
1944 RegionList::iterator i;
1947 /* don't send multiple Modified notifications
1948 when multiple regions are relayered.
1953 if (Config->get_layer_model() == MoveAddHigher ||
1954 Config->get_layer_model() == AddHigher) {
1956 RegionSortByLastLayerOp cmp;
1957 RegionList copy = regions;
1961 for (i = copy.begin(); i != copy.end(); ++i) {
1962 (*i)->set_layer (layer++);
1967 /* Session::LaterHigher model */
1969 for (i = regions.begin(); i != regions.end(); ++i) {
1970 (*i)->set_layer (layer++);
1974 /* sending Modified means that various kinds of layering
1975 models operate correctly at the GUI
1976 level. slightly inefficient, but only slightly.
1978 We force a Modified signal here in case no layers actually
1987 /* XXX these layer functions are all deprecated */
1990 Playlist::raise_region (boost::shared_ptr<Region> region)
1992 uint32_t rsz = regions.size();
1993 layer_t target = region->layer() + 1U;
1995 if (target >= rsz) {
1996 /* its already at the effective top */
2000 move_region_to_layer (target, region, 1);
2004 Playlist::lower_region (boost::shared_ptr<Region> region)
2006 if (region->layer() == 0) {
2007 /* its already at the bottom */
2011 layer_t target = region->layer() - 1U;
2013 move_region_to_layer (target, region, -1);
2017 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2019 /* does nothing useful if layering mode is later=higher */
2020 switch (Config->get_layer_model()) {
2025 RegionList::size_type sz = regions.size();
2027 if (region->layer() >= (sz - 1)) {
2028 /* already on the top */
2032 move_region_to_layer (sz, region, 1);
2033 /* mark the region's last_layer_op as now, so that it remains on top when
2034 doing future relayers (until something else takes over)
2036 timestamp_layer_op (region);
2040 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2042 /* does nothing useful if layering mode is later=higher */
2043 switch (Config->get_layer_model()) {
2048 if (region->layer() == 0) {
2049 /* already on the bottom */
2053 move_region_to_layer (0, region, -1);
2054 /* force region's last layer op to zero so that it stays at the bottom
2055 when doing future relayers
2057 region->set_last_layer_op (0);
2061 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2063 RegionList::iterator i;
2064 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2065 list<LayerInfo> layerinfo;
2069 RegionLock rlock (const_cast<Playlist *> (this));
2071 for (i = regions.begin(); i != regions.end(); ++i) {
2079 /* region is moving up, move all regions on intermediate layers
2083 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2084 dest = (*i)->layer() - 1;
2091 /* region is moving down, move all regions on intermediate layers
2095 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2096 dest = (*i)->layer() + 1;
2106 newpair.second = dest;
2108 layerinfo.push_back (newpair);
2112 /* now reset the layers without holding the region lock */
2114 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2115 x->first->set_layer (x->second);
2118 region->set_layer (target_layer);
2121 /* now check all dependents */
2123 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2124 check_dependents (x->first, false);
2127 check_dependents (region, false);
2134 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2136 RegionList::iterator i;
2143 RegionLock rlock (const_cast<Playlist *> (this));
2145 for (i = regions.begin(); i != regions.end(); ++i) {
2147 if ((*i)->position() >= start) {
2151 if ((*i)->last_frame() > max_frames - distance) {
2152 new_pos = max_frames - (*i)->length();
2154 new_pos = (*i)->position() + distance;
2159 if ((*i)->position() > distance) {
2160 new_pos = (*i)->position() - distance;
2166 (*i)->set_position (new_pos, this);
2174 notify_length_changed ();
2179 boost::shared_ptr<Region>
2180 Playlist::find_region (const ID& id) const
2182 RegionLock rlock (const_cast<Playlist*> (this));
2184 /* searches all regions currently in use by the playlist */
2186 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2187 if ((*i)->id() == id) {
2192 return boost::shared_ptr<Region> ();
2195 boost::shared_ptr<Region>
2196 Playlist::region_by_id (ID id)
2198 /* searches all regions ever added to this playlist */
2200 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2201 if ((*i)->id() == id) {
2205 return boost::shared_ptr<Region> ();
2209 Playlist::dump () const
2211 boost::shared_ptr<Region> r;
2213 cerr << "Playlist \"" << _name << "\" " << endl
2214 << regions.size() << " regions "
2217 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2219 cerr << " " << r->name() << " ["
2220 << r->start() << "+" << r->length()
2230 Playlist::set_frozen (bool yn)
2236 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2238 region->set_last_layer_op (++layer_op_counter);
2243 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2248 if (region->locked()) {
2255 RegionLock rlock (const_cast<Playlist*> (this));
2260 RegionList::iterator next;
2262 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2263 if ((*i) == region) {
2267 if (next != regions.end()) {
2269 if ((*next)->locked()) {
2273 if ((*next)->position() != region->last_frame() + 1) {
2274 /* they didn't used to touch, so after shuffle,
2275 just have them swap positions.
2277 new_pos = (*next)->position();
2279 /* they used to touch, so after shuffle,
2280 make sure they still do. put the earlier
2281 region where the later one will end after
2284 new_pos = region->position() + (*next)->length();
2287 (*next)->set_position (region->position(), this);
2288 region->set_position (new_pos, this);
2290 /* avoid a full sort */
2292 regions.erase (i); // removes the region from the list */
2294 regions.insert (next, region); // adds it back after next
2303 RegionList::iterator prev = regions.end();
2305 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2306 if ((*i) == region) {
2308 if (prev != regions.end()) {
2310 if ((*prev)->locked()) {
2314 if (region->position() != (*prev)->last_frame() + 1) {
2315 /* they didn't used to touch, so after shuffle,
2316 just have them swap positions.
2318 new_pos = region->position();
2320 /* they used to touch, so after shuffle,
2321 make sure they still do. put the earlier
2322 one where the later one will end after
2324 new_pos = (*prev)->position() + region->length();
2327 region->set_position ((*prev)->position(), this);
2328 (*prev)->set_position (new_pos, this);
2330 /* avoid a full sort */
2332 regions.erase (i); // remove region
2333 regions.insert (prev, region); // insert region before prev
2349 check_dependents (region, false);
2357 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2359 RegionLock rlock (const_cast<Playlist*> (this));
2361 if (regions.size() > 1) {
2369 Playlist::update_after_tempo_map_change ()
2371 RegionLock rlock (const_cast<Playlist*> (this));
2372 RegionList copy (regions);
2376 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2377 (*i)->update_position_after_tempo_map_change ();