2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sigc++/bind.h>
30 #include <pbd/failed_constructor.h>
31 #include <pbd/stl_delete.h>
32 #include <pbd/xml++.h>
33 #include <pbd/stacktrace.h>
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
39 #include <ardour/playlist_factory.h>
40 #include <ardour/transient_detector.h>
45 using namespace ARDOUR;
48 struct ShowMeTheList {
49 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
53 boost::shared_ptr<Playlist> playlist;
57 struct RegionSortByLayer {
58 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
59 return a->layer() < b->layer();
63 struct RegionSortByPosition {
64 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
65 return a->position() < b->position();
69 struct RegionSortByLastLayerOp {
70 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
71 return a->last_layer_op() < b->last_layer_op();
76 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
77 : SessionObject(sess, nom)
81 first_set_state = false;
86 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
87 : SessionObject(sess, "unnamed playlist")
90 const XMLProperty* prop = node.property("type");
91 assert(!prop || DataType(prop->value()) == _type);
94 _name = "unnamed"; /* reset by set_state */
96 /* set state called by derived class */
99 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
100 : SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
105 other->copy_regions (tmp);
109 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
110 add_region_internal( (*x), (*x)->position());
115 _splicing = other->_splicing;
116 _nudging = other->_nudging;
117 _edit_mode = other->_edit_mode;
120 first_set_state = false;
122 in_partition = false;
124 _read_data_count = 0;
125 _frozen = other->_frozen;
127 layer_op_counter = other->layer_op_counter;
128 freeze_length = other->freeze_length;
131 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
132 : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
134 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
136 nframes_t end = start + cnt - 1;
142 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
144 boost::shared_ptr<Region> region;
145 boost::shared_ptr<Region> new_region;
146 nframes_t offset = 0;
147 nframes_t position = 0;
154 overlap = region->coverage (start, end);
160 case OverlapInternal:
161 offset = start - region->position();
168 position = region->position() - start;
169 len = end - region->position();
173 offset = start - region->position();
175 len = region->length() - offset;
178 case OverlapExternal:
180 position = region->position() - start;
181 len = region->length();
185 _session.region_name (new_name, region->name(), false);
187 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
189 add_region_internal (new_region, position);
193 first_set_state = false;
195 /* this constructor does NOT notify others (session) */
202 InUse (true); /* EMIT SIGNAL */
213 InUse (false); /* EMIT SIGNAL */
218 Playlist::copy_regions (RegionList& newlist) const
220 RegionLock rlock (const_cast<Playlist *> (this));
222 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
223 newlist.push_back (RegionFactory::RegionFactory::create (*i));
228 Playlist::init (bool hide)
230 g_atomic_int_set (&block_notifications, 0);
231 g_atomic_int_set (&ignore_state_changes, 0);
232 pending_modified = false;
233 pending_length = false;
234 first_set_state = true;
241 _edit_mode = Config->get_edit_mode();
243 in_partition = false;
245 _read_data_count = 0;
247 layer_op_counter = 0;
250 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
253 Playlist::Playlist (const Playlist& pl)
254 : SessionObject(pl._session, pl._name)
255 , _type(pl.data_type())
257 fatal << _("playlist const copy constructor called") << endmsg;
260 Playlist::Playlist (Playlist& pl)
261 : SessionObject(pl._session, pl._name)
262 , _type(pl.data_type())
264 fatal << _("playlist non-const copy constructor called") << endmsg;
267 Playlist::~Playlist ()
270 RegionLock rl (this);
272 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
273 (*i)->set_playlist (boost::shared_ptr<Playlist>());
277 /* GoingAway must be emitted by derived classes */
281 Playlist::set_name (const string& str)
283 /* in a typical situation, a playlist is being used
284 by one diskstream and also is referenced by the
285 Session. if there are more references than that,
286 then don't change the name.
292 return SessionObject::set_name(str);
296 /***********************************************************************
297 CHANGE NOTIFICATION HANDLING
299 Notifications must be delayed till the region_lock is released. This
300 is necessary because handlers for the signals may need to acquire
301 the lock (e.g. to read from the playlist).
302 ***********************************************************************/
307 delay_notifications ();
308 g_atomic_int_inc (&ignore_state_changes);
314 g_atomic_int_dec_and_test (&ignore_state_changes);
315 release_notifications ();
320 Playlist::delay_notifications ()
322 g_atomic_int_inc (&block_notifications);
323 freeze_length = _get_maximum_extent();
327 Playlist::release_notifications ()
329 if (g_atomic_int_dec_and_test (&block_notifications)) {
330 flush_notifications ();
335 Playlist::notify_modified ()
337 if (holding_state ()) {
338 pending_modified = true;
340 pending_modified = false;
341 Modified(); /* EMIT SIGNAL */
346 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
348 if (holding_state ()) {
349 pending_removes.insert (r);
350 pending_modified = true;
351 pending_length = true;
353 /* this might not be true, but we have to act
354 as though it could be.
356 pending_length = false;
357 LengthChanged (); /* EMIT SIGNAL */
358 pending_modified = false;
359 Modified (); /* EMIT SIGNAL */
364 Playlist::notify_region_added (boost::shared_ptr<Region> r)
366 /* the length change might not be true, but we have to act
367 as though it could be.
370 if (holding_state()) {
371 pending_adds.insert (r);
372 pending_modified = true;
373 pending_length = true;
375 pending_length = false;
376 LengthChanged (); /* EMIT SIGNAL */
377 pending_modified = false;
378 Modified (); /* EMIT SIGNAL */
383 Playlist::notify_length_changed ()
385 if (holding_state ()) {
386 pending_length = true;
388 pending_length = false;
389 LengthChanged(); /* EMIT SIGNAL */
390 pending_modified = false;
391 Modified (); /* EMIT SIGNAL */
396 Playlist::flush_notifications ()
398 set<boost::shared_ptr<Region> > dependent_checks_needed;
399 set<boost::shared_ptr<Region> >::iterator s;
408 /* we have no idea what order the regions ended up in pending
409 bounds (it could be based on selection order, for example).
410 so, to preserve layering in the "most recently moved is higher"
411 model, sort them by existing layer, then timestamp them.
414 // RegionSortByLayer cmp;
415 // pending_bounds.sort (cmp);
417 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
418 if (Config->get_layer_model() == MoveAddHigher) {
419 timestamp_layer_op (*r);
421 pending_length = true;
422 dependent_checks_needed.insert (*r);
426 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
427 dependent_checks_needed.insert (*s);
431 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
432 remove_dependents (*s);
436 if ((freeze_length != _get_maximum_extent()) || pending_length) {
438 LengthChanged(); /* EMIT SIGNAL */
442 if (n || pending_modified) {
446 pending_modified = false;
447 Modified (); /* EMIT SIGNAL */
451 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
452 check_dependents (*s, false);
455 pending_adds.clear ();
456 pending_removes.clear ();
457 pending_bounds.clear ();
462 /*************************************************************
464 *************************************************************/
467 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
469 RegionLock rlock (this);
470 delay_notifications();
471 times = fabs (times);
473 int itimes = (int) floor (times);
475 nframes_t pos = position;
478 add_region_internal (region, pos);
479 pos += region->length();
484 /* note that itimes can be zero if we being asked to just
485 insert a single fraction of the region.
488 for (int i = 0; i < itimes; ++i) {
489 boost::shared_ptr<Region> copy = RegionFactory::create (region);
490 add_region_internal (copy, pos);
491 pos += region->length();
494 nframes_t length = 0;
496 if (floor (times) != times) {
497 length = (nframes_t) floor (region->length() * (times - floor (times)));
499 _session.region_name (name, region->name(), false);
500 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
501 add_region_internal (sub, pos);
505 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
506 release_notifications ();
510 Playlist::set_region_ownership ()
512 RegionLock rl (this);
513 RegionList::iterator i;
514 boost::weak_ptr<Playlist> pl (shared_from_this());
516 for (i = regions.begin(); i != regions.end(); ++i) {
517 (*i)->set_playlist (pl);
522 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
524 assert(region->data_type() == _type);
526 RegionSortByPosition cmp;
527 nframes_t old_length = 0;
529 if (!holding_state()) {
530 old_length = _get_maximum_extent();
533 if (!first_set_state) {
534 boost::shared_ptr<Playlist> foo (shared_from_this());
535 region->set_playlist (boost::weak_ptr<Playlist>(foo));
538 region->set_position (position, this);
540 timestamp_layer_op (region);
542 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
543 all_regions.insert (region);
545 possibly_splice_unlocked (position, region->length(), region);
547 if (!holding_state () && !in_set_state) {
548 /* layers get assigned from XML state */
552 /* we need to notify the existence of new region before checking dependents. Ick. */
554 notify_region_added (region);
556 if (!holding_state ()) {
557 check_dependents (region, false);
558 if (old_length != _get_maximum_extent()) {
559 notify_length_changed ();
563 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
564 boost::weak_ptr<Region> (region)));
568 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
570 RegionLock rlock (this);
572 bool old_sp = _splicing;
575 remove_region_internal (old);
576 add_region_internal (newr, pos);
580 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
584 Playlist::remove_region (boost::shared_ptr<Region> region)
586 RegionLock rlock (this);
587 remove_region_internal (region);
591 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
593 RegionList::iterator i;
594 nframes_t old_length = 0;
596 if (!holding_state()) {
597 old_length = _get_maximum_extent();
602 region->set_playlist (boost::weak_ptr<Playlist>());
605 for (i = regions.begin(); i != regions.end(); ++i) {
608 nframes_t pos = (*i)->position();
609 nframes64_t distance = (*i)->length();
613 possibly_splice_unlocked (pos, -distance);
615 if (!holding_state ()) {
617 remove_dependents (region);
619 if (old_length != _get_maximum_extent()) {
620 notify_length_changed ();
624 notify_region_removed (region);
635 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
637 if (Config->get_use_overlap_equivalency()) {
638 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
639 if ((*i)->overlap_equivalent (other)) {
640 results.push_back ((*i));
644 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
645 if ((*i)->equivalent (other)) {
646 results.push_back ((*i));
653 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
655 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
657 if ((*i) && (*i)->region_list_equivalent (other)) {
658 results.push_back (*i);
664 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
668 partition_internal (start, end, false, thawlist);
670 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
671 (*i)->thaw ("separation");
676 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
678 RegionList new_regions;
681 RegionLock rlock (this);
682 boost::shared_ptr<Region> region;
683 boost::shared_ptr<Region> current;
685 RegionList::iterator tmp;
687 nframes_t pos1, pos2, pos3, pos4;
691 /* need to work from a copy, because otherwise the regions we add during the process
692 get operated on as well.
695 RegionList copy = regions;
697 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
704 if (current->first_frame() >= start && current->last_frame() < end) {
706 remove_region_internal (current);
711 /* coverage will return OverlapStart if the start coincides
712 with the end point. we do not partition such a region,
713 so catch this special case.
716 if (current->first_frame() >= end) {
720 if ((overlap = current->coverage (start, end)) == OverlapNone) {
724 pos1 = current->position();
727 pos4 = current->last_frame();
729 if (overlap == OverlapInternal) {
731 /* split: we need 3 new regions, the front, middle and end.
732 cut: we need 2 regions, the front and end.
737 ---------------*************************------------
740 ---------------*****++++++++++++++++====------------
742 ---------------*****----------------====------------
748 /* "middle" ++++++ */
750 _session.region_name (new_name, current->name(), false);
751 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
752 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
753 add_region_internal (region, start);
754 new_regions.push_back (region);
759 _session.region_name (new_name, current->name(), false);
760 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
761 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
763 add_region_internal (region, end);
764 new_regions.push_back (region);
769 thawlist.push_back (current);
770 current->trim_end (pos2, this);
772 } else if (overlap == OverlapEnd) {
776 ---------------*************************------------
779 ---------------**************+++++++++++------------
781 ---------------**************-----------------------
788 _session.region_name (new_name, current->name(), false);
789 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
790 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
791 add_region_internal (region, start);
792 new_regions.push_back (region);
798 thawlist.push_back (current);
799 current->trim_end (pos2, this);
801 } else if (overlap == OverlapStart) {
803 /* split: we need 2 regions: the front and the end.
804 cut: just trim current to skip the cut area
809 ---------------*************************------------
813 ---------------****+++++++++++++++++++++------------
815 -------------------*********************------------
822 _session.region_name (new_name, current->name(), false);
823 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
824 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
825 add_region_internal (region, pos1);
826 new_regions.push_back (region);
832 thawlist.push_back (current);
833 current->trim_front (pos3, this);
835 } else if (overlap == OverlapExternal) {
837 /* split: no split required.
838 cut: remove the region.
843 ---------------*************************------------
847 ---------------*************************------------
849 ----------------------------------------------------
854 remove_region_internal (current);
856 new_regions.push_back (current);
860 in_partition = false;
863 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
864 check_dependents (*i, false);
868 boost::shared_ptr<Playlist>
869 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
871 boost::shared_ptr<Playlist> ret;
872 boost::shared_ptr<Playlist> pl;
875 if (ranges.empty()) {
876 return boost::shared_ptr<Playlist>();
879 start = ranges.front().start;
881 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
883 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
885 if (i == ranges.begin()) {
889 /* paste the next section into the nascent playlist,
890 offset to reflect the start of the first range we
894 ret->paste (pl, (*i).start - start, 1.0f);
901 boost::shared_ptr<Playlist>
902 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
904 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
905 return cut_copy (pmf, ranges, result_is_hidden);
908 boost::shared_ptr<Playlist>
909 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
911 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
912 return cut_copy (pmf, ranges, result_is_hidden);
915 boost::shared_ptr<Playlist>
916 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
918 boost::shared_ptr<Playlist> the_copy;
922 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
923 string new_name = _name;
927 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
928 return boost::shared_ptr<Playlist>();
931 partition_internal (start, start+cnt-1, true, thawlist);
933 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
934 (*i)->thaw ("playlist cut");
940 boost::shared_ptr<Playlist>
941 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
945 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
946 string new_name = _name;
950 cnt = min (_get_maximum_extent() - start, cnt);
951 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
955 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
957 times = fabs (times);
958 nframes_t old_length;
961 RegionLock rl1 (this);
962 RegionLock rl2 (other.get());
964 old_length = _get_maximum_extent();
966 int itimes = (int) floor (times);
967 nframes_t pos = position;
968 nframes_t shift = other->_get_maximum_extent();
969 layer_t top_layer = regions.size();
972 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
973 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
975 /* put these new regions on top of all existing ones, but preserve
976 the ordering they had in the original playlist.
979 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
980 add_region_internal (copy_of_region, copy_of_region->position() + pos);
986 /* XXX shall we handle fractional cases at some point? */
988 if (old_length != _get_maximum_extent()) {
989 notify_length_changed ();
1000 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1002 times = fabs (times);
1004 RegionLock rl (this);
1005 int itimes = (int) floor (times);
1006 nframes_t pos = position;
1009 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1010 add_region_internal (copy, pos);
1011 pos += region->length();
1014 if (floor (times) != times) {
1015 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1017 _session.region_name (name, region->name(), false);
1018 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1019 add_region_internal (sub, pos);
1024 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1026 RegionLock rlock (this);
1027 RegionList copy (regions);
1030 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1032 if ((*r)->last_frame() < at) {
1037 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1038 /* intersected region */
1039 if (!move_intersected) {
1044 /* do not move regions glued to music time - that
1045 has to be done separately.
1048 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1049 fixup.push_back (*r);
1053 (*r)->set_position ((*r)->position() + distance, this);
1056 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1057 (*r)->recompute_position_from_lock_style ();
1062 Playlist::split (nframes64_t at)
1064 RegionLock rlock (this);
1065 RegionList copy (regions);
1067 /* use a copy since this operation can modify the region list
1070 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1071 _split_region (*r, at);
1076 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1078 RegionLock rl (this);
1079 _split_region (region, playlist_position);
1083 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1085 if (!region->covers (playlist_position)) {
1089 if (region->position() == playlist_position ||
1090 region->last_frame() == playlist_position) {
1094 boost::shared_ptr<Region> left;
1095 boost::shared_ptr<Region> right;
1101 /* split doesn't change anything about length, so don't try to splice */
1103 bool old_sp = _splicing;
1106 before = playlist_position - region->position();
1107 after = region->length() - before;
1109 _session.region_name (before_name, region->name(), false);
1110 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1112 _session.region_name (after_name, region->name(), false);
1113 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1115 add_region_internal (left, region->position());
1116 add_region_internal (right, region->position() + before);
1118 uint64_t orig_layer_op = region->last_layer_op();
1119 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1120 if ((*i)->last_layer_op() > orig_layer_op) {
1121 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1125 left->set_last_layer_op ( orig_layer_op );
1126 right->set_last_layer_op ( orig_layer_op + 1);
1130 finalize_split_region (region, left, right);
1132 remove_region_internal (region);
1138 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1140 if (_splicing || in_set_state) {
1141 /* don't respond to splicing moves or state setting */
1145 if (_edit_mode == Splice) {
1146 splice_locked (at, distance, exclude);
1151 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1153 if (_splicing || in_set_state) {
1154 /* don't respond to splicing moves or state setting */
1158 if (_edit_mode == Splice) {
1159 splice_unlocked (at, distance, exclude);
1164 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1167 RegionLock rl (this);
1168 core_splice (at, distance, exclude);
1173 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1175 core_splice (at, distance, exclude);
1179 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1183 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1185 if (exclude && (*i) == exclude) {
1189 if ((*i)->position() >= at) {
1190 nframes64_t new_pos = (*i)->position() + distance;
1193 } else if (new_pos >= max_frames - (*i)->length()) {
1194 new_pos = max_frames - (*i)->length();
1197 (*i)->set_position (new_pos, this);
1203 notify_length_changed ();
1207 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1209 if (in_set_state || _splicing || _nudging || _shuffling) {
1213 if (what_changed & ARDOUR::PositionChanged) {
1215 /* remove it from the list then add it back in
1216 the right place again.
1219 RegionSortByPosition cmp;
1221 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1223 if (i == regions.end()) {
1224 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1225 _name, region->name())
1231 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1234 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1236 nframes64_t delta = 0;
1238 if (what_changed & ARDOUR::PositionChanged) {
1239 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1242 if (what_changed & ARDOUR::LengthChanged) {
1243 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1247 possibly_splice (region->last_position() + region->last_length(), delta, region);
1250 if (holding_state ()) {
1251 pending_bounds.push_back (region);
1253 if (Config->get_layer_model() == MoveAddHigher) {
1254 /* it moved or changed length, so change the timestamp */
1255 timestamp_layer_op (region);
1258 notify_length_changed ();
1260 check_dependents (region, false);
1266 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1268 boost::shared_ptr<Region> region (weak_region.lock());
1275 /* this makes a virtual call to the right kind of playlist ... */
1277 region_changed (what_changed, region);
1281 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1283 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1286 if (in_set_state || in_flush) {
1291 if (what_changed & BoundsChanged) {
1292 region_bounds_changed (what_changed, region);
1293 save = !(_splicing || _nudging);
1296 if ((what_changed & our_interests) &&
1297 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1298 check_dependents (region, false);
1301 if (what_changed & our_interests) {
1310 Playlist::drop_regions ()
1312 RegionLock rl (this);
1314 all_regions.clear ();
1318 Playlist::clear (bool with_signals)
1321 RegionLock rl (this);
1322 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1323 pending_removes.insert (*i);
1329 pending_length = false;
1331 pending_modified = false;
1337 /***********************************************************************
1339 **********************************************************************/
1341 Playlist::RegionList *
1342 Playlist::regions_at (nframes_t frame)
1345 RegionLock rlock (this);
1346 return find_regions_at (frame);
1349 boost::shared_ptr<Region>
1350 Playlist::top_region_at (nframes_t frame)
1353 RegionLock rlock (this);
1354 RegionList *rlist = find_regions_at (frame);
1355 boost::shared_ptr<Region> region;
1357 if (rlist->size()) {
1358 RegionSortByLayer cmp;
1360 region = rlist->back();
1367 Playlist::RegionList*
1368 Playlist::regions_to_read (nframes_t start, nframes_t end)
1370 /* Caller must hold lock */
1372 RegionList covering;
1373 set<nframes_t> to_check;
1374 set<boost::shared_ptr<Region> > unique;
1377 to_check.insert (start);
1378 to_check.insert (end);
1380 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1382 /* find all/any regions that span start+end */
1384 switch ((*i)->coverage (start, end)) {
1388 case OverlapInternal:
1389 covering.push_back (*i);
1393 to_check.insert ((*i)->position());
1394 covering.push_back (*i);
1398 to_check.insert ((*i)->last_frame());
1399 covering.push_back (*i);
1402 case OverlapExternal:
1403 covering.push_back (*i);
1404 to_check.insert ((*i)->position());
1405 to_check.insert ((*i)->last_frame());
1409 /* don't go too far */
1411 if ((*i)->position() > end) {
1416 RegionList* rlist = new RegionList;
1418 /* find all the regions that cover each position .... */
1420 if (covering.size() == 1) {
1422 rlist->push_back (covering.front());
1426 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1430 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1432 if ((*x)->covers (*t)) {
1433 here.push_back (*x);
1437 RegionSortByLayer cmp;
1440 /* ... and get the top/transparent regions at "here" */
1442 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1446 if ((*c)->opaque()) {
1448 /* the other regions at this position are hidden by this one */
1455 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1456 rlist->push_back (*s);
1459 if (rlist->size() > 1) {
1460 /* now sort by time order */
1462 RegionSortByPosition cmp;
1470 Playlist::RegionList *
1471 Playlist::find_regions_at (nframes_t frame)
1473 /* Caller must hold lock */
1475 RegionList *rlist = new RegionList;
1477 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1478 if ((*i)->covers (frame)) {
1479 rlist->push_back (*i);
1486 Playlist::RegionList *
1487 Playlist::regions_touched (nframes_t start, nframes_t end)
1489 RegionLock rlock (this);
1490 RegionList *rlist = new RegionList;
1492 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1493 if ((*i)->coverage (start, end) != OverlapNone) {
1494 rlist->push_back (*i);
1502 Playlist::find_next_transient (nframes64_t from, int dir)
1504 RegionLock rlock (this);
1505 AnalysisFeatureList points;
1506 AnalysisFeatureList these_points;
1508 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1510 if ((*i)->last_frame() < from) {
1514 if ((*i)->first_frame() > from) {
1519 (*i)->get_transients (these_points);
1521 /* add first frame, just, err, because */
1523 these_points.push_back ((*i)->first_frame());
1525 points.insert (points.end(), these_points.begin(), these_points.end());
1526 these_points.clear ();
1529 if (points.empty()) {
1533 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1534 bool reached = false;
1537 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1542 if (reached && (*x) > from) {
1547 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1552 if (reached && (*x) < from) {
1561 boost::shared_ptr<Region>
1562 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1564 RegionLock rlock (this);
1565 boost::shared_ptr<Region> ret;
1566 nframes_t closest = max_frames;
1569 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1572 boost::shared_ptr<Region> r = (*i);
1577 pos = r->first_frame ();
1580 pos = r->last_frame ();
1583 pos = r->adjust_to_sync (r->first_frame());
1588 case 1: /* forwards */
1591 if ((distance = pos - frame) < closest) {
1599 default: /* backwards */
1602 if ((distance = frame - pos) < closest) {
1615 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1617 RegionLock rlock (this);
1619 nframes64_t closest = max_frames;
1620 nframes64_t ret = -1;
1624 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1626 boost::shared_ptr<Region> r = (*i);
1627 nframes64_t distance;
1628 nframes64_t end = r->position() + r->length();
1633 if (r->first_frame() > frame) {
1635 distance = r->first_frame() - frame;
1637 if (distance < closest) {
1638 ret = r->first_frame();
1646 distance = end - frame;
1648 if (distance < closest) {
1662 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1664 boost::shared_ptr<Region> r = (*i);
1665 nframes64_t distance;
1670 if (r->last_frame() < frame) {
1672 distance = frame - r->last_frame();
1674 if (distance < closest) {
1675 ret = r->last_frame();
1681 if (r->first_frame() < frame) {
1682 distance = frame - r->last_frame();
1684 if (distance < closest) {
1685 ret = r->first_frame();
1700 /***********************************************************************/
1705 Playlist::mark_session_dirty ()
1707 if (!in_set_state && !holding_state ()) {
1708 _session.set_dirty();
1713 Playlist::set_state (const XMLNode& node)
1717 XMLNodeConstIterator niter;
1718 XMLPropertyList plist;
1719 XMLPropertyConstIterator piter;
1721 boost::shared_ptr<Region> region;
1726 if (node.name() != "Playlist") {
1733 plist = node.properties();
1735 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1739 if (prop->name() == X_("name")) {
1740 _name = prop->value();
1741 } else if (prop->name() == X_("orig_diskstream_id")) {
1742 _orig_diskstream_id = prop->value ();
1743 } else if (prop->name() == X_("frozen")) {
1744 _frozen = (prop->value() == X_("yes"));
1750 nlist = node.children();
1752 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1756 if (child->name() == "Region") {
1758 if ((prop = child->property ("id")) == 0) {
1759 error << _("region state node has no ID, ignored") << endmsg;
1763 ID id = prop->value ();
1765 if ((region = region_by_id (id))) {
1767 Change what_changed = Change (0);
1769 if (region->set_live_state (*child, what_changed, true)) {
1770 error << _("Playlist: cannot reset region state from XML") << endmsg;
1774 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1775 error << _("Playlist: cannot create region from XML") << endmsg;
1779 add_region (region, region->position(), 1.0);
1781 // So that layer_op ordering doesn't get screwed up
1782 region->set_last_layer_op( region->layer());
1791 /* update dependents, which was not done during add_region_internal
1792 due to in_set_state being true
1795 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1796 check_dependents (*r, false);
1800 first_set_state = false;
1805 Playlist::get_state()
1811 Playlist::get_template()
1813 return state(false);
1817 Playlist::state (bool full_state)
1819 XMLNode *node = new XMLNode (X_("Playlist"));
1822 node->add_property (X_("name"), _name);
1823 node->add_property (X_("type"), _type.to_string());
1825 _orig_diskstream_id.print (buf, sizeof (buf));
1826 node->add_property (X_("orig_diskstream_id"), buf);
1827 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1830 RegionLock rlock (this, false);
1831 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1832 node->add_child_nocopy ((*i)->get_state());
1837 node->add_child_copy (*_extra_xml);
1844 Playlist::empty() const
1846 RegionLock rlock (const_cast<Playlist *>(this), false);
1847 return regions.empty();
1851 Playlist::n_regions() const
1853 RegionLock rlock (const_cast<Playlist *>(this), false);
1854 return regions.size();
1858 Playlist::get_maximum_extent () const
1860 RegionLock rlock (const_cast<Playlist *>(this), false);
1861 return _get_maximum_extent ();
1865 Playlist::_get_maximum_extent () const
1867 RegionList::const_iterator i;
1868 nframes_t max_extent = 0;
1871 for (i = regions.begin(); i != regions.end(); ++i) {
1872 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1881 Playlist::bump_name (string name, Session &session)
1883 string newname = name;
1886 newname = bump_name_once (newname);
1887 } while (session.playlist_by_name (newname)!=NULL);
1894 Playlist::top_layer() const
1896 RegionLock rlock (const_cast<Playlist *> (this));
1899 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1900 top = max (top, (*i)->layer());
1906 Playlist::set_edit_mode (EditMode mode)
1911 /********************
1913 ********************/
1916 Playlist::relayer ()
1918 /* don't send multiple Modified notifications
1919 when multiple regions are relayered.
1924 /* build up a new list of regions on each layer */
1926 std::vector<RegionList> layers;
1928 /* we want to go through regions from desired lowest to desired highest layer,
1929 which depends on the layer model
1932 RegionList copy = regions;
1934 /* sort according to the model */
1936 if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
1937 RegionSortByLastLayerOp cmp;
1941 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1943 /* find the lowest layer that this region can go on */
1944 size_t j = layers.size();
1946 /* try layer j - 1; it can go on if it overlaps no other region
1947 that is already on that layer
1949 RegionList::iterator k = layers[j - 1].begin();
1950 while (k != layers[j - 1].end()) {
1951 if ((*k)->overlap_equivalent (*i)) {
1957 if (k != layers[j - 1].end()) {
1958 /* no overlap, so we can use this layer */
1965 if (j == layers.size()) {
1966 /* we need a new layer for this region */
1967 layers.push_back (RegionList ());
1970 layers[j].push_back (*i);
1973 /* first pass: set up the layer numbers in the regions */
1974 for (size_t j = 0; j < layers.size(); ++j) {
1975 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
1976 (*i)->set_layer (j);
1980 /* sending Modified means that various kinds of layering
1981 models operate correctly at the GUI
1982 level. slightly inefficient, but only slightly.
1984 We force a Modified signal here in case no layers actually
1993 /* XXX these layer functions are all deprecated */
1996 Playlist::raise_region (boost::shared_ptr<Region> region)
1998 uint32_t rsz = regions.size();
1999 layer_t target = region->layer() + 1U;
2001 if (target >= rsz) {
2002 /* its already at the effective top */
2006 move_region_to_layer (target, region, 1);
2010 Playlist::lower_region (boost::shared_ptr<Region> region)
2012 if (region->layer() == 0) {
2013 /* its already at the bottom */
2017 layer_t target = region->layer() - 1U;
2019 move_region_to_layer (target, region, -1);
2023 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2025 /* does nothing useful if layering mode is later=higher */
2026 if ((Config->get_layer_model() == MoveAddHigher) ||
2027 (Config->get_layer_model() == AddHigher)) {
2028 timestamp_layer_op (region);
2034 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2036 /* does nothing useful if layering mode is later=higher */
2037 if ((Config->get_layer_model() == MoveAddHigher) ||
2038 (Config->get_layer_model() == AddHigher)) {
2039 region->set_last_layer_op (0);
2045 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2047 RegionList::iterator i;
2048 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2049 list<LayerInfo> layerinfo;
2053 RegionLock rlock (const_cast<Playlist *> (this));
2055 for (i = regions.begin(); i != regions.end(); ++i) {
2063 /* region is moving up, move all regions on intermediate layers
2067 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2068 dest = (*i)->layer() - 1;
2075 /* region is moving down, move all regions on intermediate layers
2079 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2080 dest = (*i)->layer() + 1;
2090 newpair.second = dest;
2092 layerinfo.push_back (newpair);
2096 /* now reset the layers without holding the region lock */
2098 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2099 x->first->set_layer (x->second);
2102 region->set_layer (target_layer);
2105 /* now check all dependents */
2107 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2108 check_dependents (x->first, false);
2111 check_dependents (region, false);
2118 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2120 RegionList::iterator i;
2127 RegionLock rlock (const_cast<Playlist *> (this));
2129 for (i = regions.begin(); i != regions.end(); ++i) {
2131 if ((*i)->position() >= start) {
2135 if ((*i)->last_frame() > max_frames - distance) {
2136 new_pos = max_frames - (*i)->length();
2138 new_pos = (*i)->position() + distance;
2143 if ((*i)->position() > distance) {
2144 new_pos = (*i)->position() - distance;
2150 (*i)->set_position (new_pos, this);
2158 notify_length_changed ();
2163 boost::shared_ptr<Region>
2164 Playlist::find_region (const ID& id) const
2166 RegionLock rlock (const_cast<Playlist*> (this));
2168 /* searches all regions currently in use by the playlist */
2170 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2171 if ((*i)->id() == id) {
2176 return boost::shared_ptr<Region> ();
2179 boost::shared_ptr<Region>
2180 Playlist::region_by_id (ID id)
2182 /* searches all regions ever added to this playlist */
2184 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2185 if ((*i)->id() == id) {
2189 return boost::shared_ptr<Region> ();
2193 Playlist::dump () const
2195 boost::shared_ptr<Region> r;
2197 cerr << "Playlist \"" << _name << "\" " << endl
2198 << regions.size() << " regions "
2201 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2203 cerr << " " << r->name() << " ["
2204 << r->start() << "+" << r->length()
2214 Playlist::set_frozen (bool yn)
2220 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2222 // struct timeval tv;
2223 // gettimeofday (&tv, 0);
2224 region->set_last_layer_op (++layer_op_counter);
2229 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2234 if (region->locked()) {
2241 RegionLock rlock (const_cast<Playlist*> (this));
2246 RegionList::iterator next;
2248 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2249 if ((*i) == region) {
2253 if (next != regions.end()) {
2255 if ((*next)->locked()) {
2259 if ((*next)->position() != region->last_frame() + 1) {
2260 /* they didn't used to touch, so after shuffle,
2261 just have them swap positions.
2263 new_pos = (*next)->position();
2265 /* they used to touch, so after shuffle,
2266 make sure they still do. put the earlier
2267 region where the later one will end after
2270 new_pos = region->position() + (*next)->length();
2273 (*next)->set_position (region->position(), this);
2274 region->set_position (new_pos, this);
2276 /* avoid a full sort */
2278 regions.erase (i); // removes the region from the list */
2280 regions.insert (next, region); // adds it back after next
2289 RegionList::iterator prev = regions.end();
2291 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2292 if ((*i) == region) {
2294 if (prev != regions.end()) {
2296 if ((*prev)->locked()) {
2300 if (region->position() != (*prev)->last_frame() + 1) {
2301 /* they didn't used to touch, so after shuffle,
2302 just have them swap positions.
2304 new_pos = region->position();
2306 /* they used to touch, so after shuffle,
2307 make sure they still do. put the earlier
2308 one where the later one will end after
2310 new_pos = (*prev)->position() + region->length();
2313 region->set_position ((*prev)->position(), this);
2314 (*prev)->set_position (new_pos, this);
2316 /* avoid a full sort */
2318 regions.erase (i); // remove region
2319 regions.insert (prev, region); // insert region before prev
2335 check_dependents (region, false);
2343 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2345 RegionLock rlock (const_cast<Playlist*> (this));
2347 if (regions.size() > 1) {
2355 Playlist::update_after_tempo_map_change ()
2357 RegionLock rlock (const_cast<Playlist*> (this));
2358 RegionList copy (regions);
2362 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2363 (*i)->update_position_after_tempo_map_change ();