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();
75 Playlist::Playlist (Session& sess, string nom, bool hide)
79 first_set_state = false;
84 Playlist::Playlist (Session& sess, const XMLNode& node, bool hide)
88 _name = "unnamed"; /* reset by set_state */
90 /* set state called by derived class */
93 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
94 : _name (namestr), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
99 other->copy_regions (tmp);
103 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
104 add_region_internal( (*x), (*x)->position());
109 _splicing = other->_splicing;
110 _nudging = other->_nudging;
111 _edit_mode = other->_edit_mode;
114 first_set_state = false;
116 in_partition = false;
118 _read_data_count = 0;
119 _frozen = other->_frozen;
121 layer_op_counter = other->layer_op_counter;
122 freeze_length = other->freeze_length;
125 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
126 : _name (str), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
128 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
130 nframes_t end = start + cnt - 1;
136 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
138 boost::shared_ptr<Region> region;
139 boost::shared_ptr<Region> new_region;
140 nframes_t offset = 0;
141 nframes_t position = 0;
148 overlap = region->coverage (start, end);
154 case OverlapInternal:
155 offset = start - region->position();
162 position = region->position() - start;
163 len = end - region->position();
167 offset = start - region->position();
169 len = region->length() - offset;
172 case OverlapExternal:
174 position = region->position() - start;
175 len = region->length();
179 _session.region_name (new_name, region->name(), false);
181 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
183 add_region_internal (new_region, position);
187 first_set_state = false;
189 /* this constructor does NOT notify others (session) */
196 InUse (true); /* EMIT SIGNAL */
207 InUse (false); /* EMIT SIGNAL */
212 Playlist::copy_regions (RegionList& newlist) const
214 RegionLock rlock (const_cast<Playlist *> (this));
216 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
217 newlist.push_back (RegionFactory::RegionFactory::create (*i));
222 Playlist::init (bool hide)
224 g_atomic_int_set (&block_notifications, 0);
225 g_atomic_int_set (&ignore_state_changes, 0);
226 pending_modified = false;
227 pending_length = false;
228 first_set_state = true;
235 _edit_mode = Config->get_edit_mode();
237 in_partition = false;
239 _read_data_count = 0;
241 layer_op_counter = 0;
244 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
247 Playlist::Playlist (const Playlist& pl)
248 : _session (pl._session)
250 fatal << _("playlist const copy constructor called") << endmsg;
253 Playlist::Playlist (Playlist& pl)
254 : _session (pl._session)
256 fatal << _("playlist non-const copy constructor called") << endmsg;
259 Playlist::~Playlist ()
262 RegionLock rl (this);
264 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
265 (*i)->set_playlist (boost::shared_ptr<Playlist>());
269 /* GoingAway must be emitted by derived classes */
273 Playlist::set_name (string str)
275 /* in a typical situation, a playlist is being used
276 by one diskstream and also is referenced by the
277 Session. if there are more references than that,
278 then don't change the name.
291 while (_session.playlist_by_name(name) != 0) {
292 name = bump_name_once(name);
296 NameChanged(); /* EMIT SIGNAL */
299 /***********************************************************************
300 CHANGE NOTIFICATION HANDLING
302 Notifications must be delayed till the region_lock is released. This
303 is necessary because handlers for the signals may need to acquire
304 the lock (e.g. to read from the playlist).
305 ***********************************************************************/
310 delay_notifications ();
311 g_atomic_int_inc (&ignore_state_changes);
317 g_atomic_int_dec_and_test (&ignore_state_changes);
318 release_notifications ();
323 Playlist::delay_notifications ()
325 g_atomic_int_inc (&block_notifications);
326 freeze_length = _get_maximum_extent();
330 Playlist::release_notifications ()
332 if (g_atomic_int_dec_and_test (&block_notifications)) {
333 flush_notifications ();
339 Playlist::notify_modified ()
341 if (holding_state ()) {
342 pending_modified = true;
344 pending_modified = false;
345 Modified(); /* EMIT SIGNAL */
350 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
352 if (holding_state ()) {
353 pending_removes.insert (r);
354 pending_modified = true;
355 pending_length = true;
357 /* this might not be true, but we have to act
358 as though it could be.
360 LengthChanged (); /* EMIT SIGNAL */
361 Modified (); /* EMIT SIGNAL */
366 Playlist::notify_region_added (boost::shared_ptr<Region> r)
368 /* the length change might not be true, but we have to act
369 as though it could be.
372 if (holding_state()) {
373 pending_adds.insert (r);
374 pending_modified = true;
375 pending_length = true;
377 LengthChanged (); /* EMIT SIGNAL */
378 Modified (); /* EMIT SIGNAL */
383 Playlist::notify_length_changed ()
385 if (holding_state ()) {
386 pending_length = true;
388 LengthChanged(); /* EMIT SIGNAL */
389 Modified (); /* EMIT SIGNAL */
394 Playlist::flush_notifications ()
396 set<boost::shared_ptr<Region> > dependent_checks_needed;
397 set<boost::shared_ptr<Region> >::iterator s;
406 /* we have no idea what order the regions ended up in pending
407 bounds (it could be based on selection order, for example).
408 so, to preserve layering in the "most recently moved is higher"
409 model, sort them by existing layer, then timestamp them.
412 // RegionSortByLayer cmp;
413 // pending_bounds.sort (cmp);
415 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
416 if (Config->get_layer_model() == MoveAddHigher) {
417 timestamp_layer_op (*r);
419 pending_length = true;
420 dependent_checks_needed.insert (*r);
424 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
425 dependent_checks_needed.insert (*s);
429 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
430 remove_dependents (*s);
434 if ((freeze_length != _get_maximum_extent()) || pending_length) {
436 LengthChanged(); /* EMIT SIGNAL */
440 if (n || pending_modified) {
444 pending_modified = false;
445 Modified (); /* EMIT SIGNAL */
448 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
449 check_dependents (*s, false);
452 pending_adds.clear ();
453 pending_removes.clear ();
454 pending_bounds.clear ();
459 /*************************************************************
461 *************************************************************/
464 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
466 RegionLock rlock (this);
468 times = fabs (times);
470 int itimes = (int) floor (times);
472 nframes_t pos = position;
475 add_region_internal (region, pos);
476 pos += region->length();
481 /* note that itimes can be zero if we being asked to just
482 insert a single fraction of the region.
485 for (int i = 0; i < itimes; ++i) {
486 boost::shared_ptr<Region> copy = RegionFactory::create (region);
487 add_region_internal (copy, pos);
488 pos += region->length();
491 nframes_t length = 0;
493 if (floor (times) != times) {
494 length = (nframes_t) floor (region->length() * (times - floor (times)));
496 _session.region_name (name, region->name(), false);
497 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
498 add_region_internal (sub, pos);
502 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
506 Playlist::set_region_ownership ()
508 RegionLock rl (this);
509 RegionList::iterator i;
510 boost::weak_ptr<Playlist> pl (shared_from_this());
512 for (i = regions.begin(); i != regions.end(); ++i) {
513 (*i)->set_playlist (pl);
518 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
520 RegionSortByPosition cmp;
521 nframes_t old_length = 0;
523 if (!holding_state()) {
524 old_length = _get_maximum_extent();
527 if (!first_set_state) {
528 boost::shared_ptr<Playlist> foo (shared_from_this());
529 region->set_playlist (boost::weak_ptr<Playlist>(foo));
532 region->set_position (position, this);
534 timestamp_layer_op (region);
536 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
537 all_regions.insert (region);
539 possibly_splice_unlocked (position, region->length(), region);
541 if (!holding_state () && !in_set_state) {
542 /* layers get assigned from XML state */
546 /* we need to notify the existence of new region before checking dependents. Ick. */
548 notify_region_added (region);
550 if (!holding_state ()) {
551 check_dependents (region, false);
552 if (old_length != _get_maximum_extent()) {
553 notify_length_changed ();
557 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
558 boost::weak_ptr<Region> (region)));
562 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
564 RegionLock rlock (this);
566 bool old_sp = _splicing;
569 remove_region_internal (old);
570 add_region_internal (newr, pos);
574 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
578 Playlist::remove_region (boost::shared_ptr<Region> region)
580 RegionLock rlock (this);
581 remove_region_internal (region);
585 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
587 RegionList::iterator i;
588 nframes_t old_length = 0;
590 if (!holding_state()) {
591 old_length = _get_maximum_extent();
596 region->set_playlist (boost::weak_ptr<Playlist>());
599 for (i = regions.begin(); i != regions.end(); ++i) {
602 nframes_t pos = (*i)->position();
603 nframes64_t distance = (*i)->length();
607 possibly_splice_unlocked (pos, -distance);
609 if (!holding_state ()) {
611 remove_dependents (region);
613 if (old_length != _get_maximum_extent()) {
614 notify_length_changed ();
618 notify_region_removed (region);
629 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
631 if (Config->get_use_overlap_equivalency()) {
632 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
633 if ((*i)->overlap_equivalent (other)) {
634 results.push_back ((*i));
638 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
639 if ((*i)->equivalent (other)) {
640 results.push_back ((*i));
647 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
649 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
651 if ((*i) && (*i)->region_list_equivalent (other)) {
652 results.push_back (*i);
658 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
662 partition_internal (start, end, false, thawlist);
664 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
665 (*i)->thaw ("separation");
670 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
672 RegionList new_regions;
675 RegionLock rlock (this);
676 boost::shared_ptr<Region> region;
677 boost::shared_ptr<Region> current;
679 RegionList::iterator tmp;
681 nframes_t pos1, pos2, pos3, pos4;
685 /* need to work from a copy, because otherwise the regions we add during the process
686 get operated on as well.
689 RegionList copy = regions;
691 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
698 if (current->first_frame() >= start && current->last_frame() < end) {
700 remove_region_internal (current);
705 /* coverage will return OverlapStart if the start coincides
706 with the end point. we do not partition such a region,
707 so catch this special case.
710 if (current->first_frame() >= end) {
714 if ((overlap = current->coverage (start, end)) == OverlapNone) {
718 pos1 = current->position();
721 pos4 = current->last_frame();
723 if (overlap == OverlapInternal) {
725 /* split: we need 3 new regions, the front, middle and end.
726 cut: we need 2 regions, the front and end.
731 ---------------*************************------------
734 ---------------*****++++++++++++++++====------------
736 ---------------*****----------------====------------
742 /* "middle" ++++++ */
744 _session.region_name (new_name, current->name(), false);
745 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
746 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
747 add_region_internal (region, start);
748 new_regions.push_back (region);
753 _session.region_name (new_name, current->name(), false);
754 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
755 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
757 add_region_internal (region, end);
758 new_regions.push_back (region);
763 thawlist.push_back (current);
764 current->trim_end (pos2, this);
766 } else if (overlap == OverlapEnd) {
770 ---------------*************************------------
773 ---------------**************+++++++++++------------
775 ---------------**************-----------------------
782 _session.region_name (new_name, current->name(), false);
783 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
784 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
785 add_region_internal (region, start);
786 new_regions.push_back (region);
792 thawlist.push_back (current);
793 current->trim_end (pos2, this);
795 } else if (overlap == OverlapStart) {
797 /* split: we need 2 regions: the front and the end.
798 cut: just trim current to skip the cut area
803 ---------------*************************------------
807 ---------------****+++++++++++++++++++++------------
809 -------------------*********************------------
816 _session.region_name (new_name, current->name(), false);
817 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
818 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
819 add_region_internal (region, pos1);
820 new_regions.push_back (region);
826 thawlist.push_back (current);
827 current->trim_front (pos3, this);
829 } else if (overlap == OverlapExternal) {
831 /* split: no split required.
832 cut: remove the region.
837 ---------------*************************------------
841 ---------------*************************------------
843 ----------------------------------------------------
848 remove_region_internal (current);
850 new_regions.push_back (current);
854 if (current->first_frame() >= current->last_frame()) {
855 PBD::stacktrace (cerr);
858 in_partition = false;
861 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
862 check_dependents (*i, false);
866 boost::shared_ptr<Playlist>
867 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
869 boost::shared_ptr<Playlist> ret;
870 boost::shared_ptr<Playlist> pl;
873 if (ranges.empty()) {
874 return boost::shared_ptr<Playlist>();
877 start = ranges.front().start;
879 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
881 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
883 if (i == ranges.begin()) {
887 /* paste the next section into the nascent playlist,
888 offset to reflect the start of the first range we
892 ret->paste (pl, (*i).start - start, 1.0f);
899 boost::shared_ptr<Playlist>
900 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
902 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
903 return cut_copy (pmf, ranges, result_is_hidden);
906 boost::shared_ptr<Playlist>
907 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
909 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
910 return cut_copy (pmf, ranges, result_is_hidden);
913 boost::shared_ptr<Playlist>
914 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
916 boost::shared_ptr<Playlist> the_copy;
920 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
921 string new_name = _name;
925 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
926 return boost::shared_ptr<Playlist>();
929 partition_internal (start, start+cnt-1, true, thawlist);
931 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
932 (*i)->thaw ("playlist cut");
938 boost::shared_ptr<Playlist>
939 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
943 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
944 string new_name = _name;
948 cnt = min (_get_maximum_extent() - start, cnt);
949 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
953 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
955 times = fabs (times);
956 nframes_t old_length;
959 RegionLock rl1 (this);
960 RegionLock rl2 (other.get());
962 old_length = _get_maximum_extent();
964 int itimes = (int) floor (times);
965 nframes_t pos = position;
966 nframes_t shift = other->_get_maximum_extent();
967 layer_t top_layer = regions.size();
970 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
971 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
973 /* put these new regions on top of all existing ones, but preserve
974 the ordering they had in the original playlist.
977 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
978 add_region_internal (copy_of_region, copy_of_region->position() + pos);
984 /* XXX shall we handle fractional cases at some point? */
986 if (old_length != _get_maximum_extent()) {
987 notify_length_changed ();
998 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1000 times = fabs (times);
1002 RegionLock rl (this);
1003 int itimes = (int) floor (times);
1004 nframes_t pos = position;
1007 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1008 add_region_internal (copy, pos);
1009 pos += region->length();
1012 if (floor (times) != times) {
1013 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1015 _session.region_name (name, region->name(), false);
1016 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1017 add_region_internal (sub, pos);
1022 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1024 RegionLock rl (this);
1026 if (!region->covers (playlist_position)) {
1030 if (region->position() == playlist_position ||
1031 region->last_frame() == playlist_position) {
1035 boost::shared_ptr<Region> left;
1036 boost::shared_ptr<Region> right;
1042 /* split doesn't change anything about length, so don't try to splice */
1044 bool old_sp = _splicing;
1047 before = playlist_position - region->position();
1048 after = region->length() - before;
1050 _session.region_name (before_name, region->name(), false);
1051 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1053 _session.region_name (after_name, region->name(), false);
1054 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1056 add_region_internal (left, region->position());
1057 add_region_internal (right, region->position() + before);
1059 uint64_t orig_layer_op = region->last_layer_op();
1060 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1061 if ((*i)->last_layer_op() > orig_layer_op) {
1062 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1066 left->set_last_layer_op ( orig_layer_op );
1067 right->set_last_layer_op ( orig_layer_op + 1);
1071 finalize_split_region (region, left, right);
1073 remove_region_internal (region);
1079 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1081 if (_splicing || in_set_state) {
1082 /* don't respond to splicing moves or state setting */
1086 if (_edit_mode == Splice) {
1087 splice_locked (at, distance, exclude);
1092 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1094 if (_splicing || in_set_state) {
1095 /* don't respond to splicing moves or state setting */
1099 if (_edit_mode == Splice) {
1100 splice_unlocked (at, distance, exclude);
1105 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1108 RegionLock rl (this);
1109 core_splice (at, distance, exclude);
1114 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1116 core_splice (at, distance, exclude);
1120 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1124 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1126 if (exclude && (*i) == exclude) {
1130 if ((*i)->position() >= at) {
1131 nframes64_t new_pos = (*i)->position() + distance;
1134 } else if (new_pos >= max_frames - (*i)->length()) {
1135 new_pos = max_frames - (*i)->length();
1138 (*i)->set_position (new_pos, this);
1144 notify_length_changed ();
1148 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1150 if (in_set_state || _splicing || _nudging || _shuffling) {
1154 if (what_changed & ARDOUR::PositionChanged) {
1156 /* remove it from the list then add it back in
1157 the right place again.
1160 RegionSortByPosition cmp;
1162 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1164 if (i == regions.end()) {
1165 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1166 _name, region->name())
1172 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1175 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1177 nframes64_t delta = 0;
1179 if (what_changed & ARDOUR::PositionChanged) {
1180 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1183 if (what_changed & ARDOUR::LengthChanged) {
1184 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1188 possibly_splice (region->last_position() + region->last_length(), delta, region);
1191 if (holding_state ()) {
1192 pending_bounds.push_back (region);
1194 if (Config->get_layer_model() == MoveAddHigher) {
1195 /* it moved or changed length, so change the timestamp */
1196 timestamp_layer_op (region);
1199 notify_length_changed ();
1201 check_dependents (region, false);
1207 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1209 boost::shared_ptr<Region> region (weak_region.lock());
1216 /* this makes a virtual call to the right kind of playlist ... */
1218 region_changed (what_changed, region);
1222 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1224 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1227 if (in_set_state || in_flush) {
1232 if (what_changed & BoundsChanged) {
1233 region_bounds_changed (what_changed, region);
1234 save = !(_splicing || _nudging);
1237 if ((what_changed & our_interests) &&
1238 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1239 check_dependents (region, false);
1242 if (what_changed & our_interests) {
1251 Playlist::drop_regions ()
1253 RegionLock rl (this);
1255 all_regions.clear ();
1259 Playlist::clear (bool with_signals)
1262 RegionLock rl (this);
1263 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1264 pending_removes.insert (*i);
1276 /***********************************************************************
1278 **********************************************************************/
1280 Playlist::RegionList *
1281 Playlist::regions_at (nframes_t frame)
1284 RegionLock rlock (this);
1285 return find_regions_at (frame);
1288 boost::shared_ptr<Region>
1289 Playlist::top_region_at (nframes_t frame)
1292 RegionLock rlock (this);
1293 RegionList *rlist = find_regions_at (frame);
1294 boost::shared_ptr<Region> region;
1296 if (rlist->size()) {
1297 RegionSortByLayer cmp;
1299 region = rlist->back();
1306 Playlist::RegionList*
1307 Playlist::regions_to_read (nframes_t start, nframes_t end)
1309 /* Caller must hold lock */
1311 RegionList covering;
1312 set<nframes_t> to_check;
1313 set<boost::shared_ptr<Region> > unique;
1316 to_check.insert (start);
1317 to_check.insert (end);
1319 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1321 /* find all/any regions that span start+end */
1323 switch ((*i)->coverage (start, end)) {
1327 case OverlapInternal:
1328 covering.push_back (*i);
1332 to_check.insert ((*i)->position());
1333 covering.push_back (*i);
1337 to_check.insert ((*i)->last_frame());
1338 covering.push_back (*i);
1341 case OverlapExternal:
1342 covering.push_back (*i);
1343 to_check.insert ((*i)->position());
1344 to_check.insert ((*i)->last_frame());
1348 /* don't go too far */
1350 if ((*i)->position() > end) {
1355 RegionList* rlist = new RegionList;
1357 /* find all the regions that cover each position .... */
1359 if (covering.size() == 1) {
1361 rlist->push_back (covering.front());
1365 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1369 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1371 if ((*x)->covers (*t)) {
1372 here.push_back (*x);
1376 RegionSortByLayer cmp;
1379 /* ... and get the top/transparent regions at "here" */
1381 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1385 if ((*c)->opaque()) {
1387 /* the other regions at this position are hidden by this one */
1394 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1395 rlist->push_back (*s);
1398 if (rlist->size() > 1) {
1399 /* now sort by time order */
1401 RegionSortByPosition cmp;
1409 Playlist::RegionList *
1410 Playlist::find_regions_at (nframes_t frame)
1412 /* Caller must hold lock */
1414 RegionList *rlist = new RegionList;
1416 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1417 if ((*i)->covers (frame)) {
1418 rlist->push_back (*i);
1425 Playlist::RegionList *
1426 Playlist::regions_touched (nframes_t start, nframes_t end)
1428 RegionLock rlock (this);
1429 RegionList *rlist = new RegionList;
1431 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1432 if ((*i)->coverage (start, end) != OverlapNone) {
1433 rlist->push_back (*i);
1441 Playlist::find_next_transient (nframes64_t from, int dir)
1443 RegionLock rlock (this);
1444 AnalysisFeatureList points;
1445 AnalysisFeatureList these_points;
1447 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1449 if ((*i)->last_frame() < from) {
1453 if ((*i)->first_frame() > from) {
1458 (*i)->get_transients (these_points);
1460 /* add first frame, just, err, because */
1462 these_points.push_back ((*i)->first_frame());
1464 points.insert (points.end(), these_points.begin(), these_points.end());
1465 these_points.clear ();
1468 if (points.empty()) {
1472 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1473 bool reached = false;
1476 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1481 if (reached && (*x) > from) {
1486 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1491 if (reached && (*x) < from) {
1500 boost::shared_ptr<Region>
1501 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1503 RegionLock rlock (this);
1504 boost::shared_ptr<Region> ret;
1505 nframes_t closest = max_frames;
1508 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1511 boost::shared_ptr<Region> r = (*i);
1516 pos = r->first_frame ();
1519 pos = r->last_frame ();
1522 pos = r->adjust_to_sync (r->first_frame());
1527 case 1: /* forwards */
1530 if ((distance = pos - frame) < closest) {
1538 default: /* backwards */
1541 if ((distance = frame - pos) < closest) {
1554 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1556 RegionLock rlock (this);
1558 nframes64_t closest = max_frames;
1559 nframes64_t ret = -1;
1563 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1565 boost::shared_ptr<Region> r = (*i);
1566 nframes64_t distance;
1567 nframes64_t end = r->position() + r->length();
1572 if (r->first_frame() > frame) {
1574 distance = r->first_frame() - frame;
1576 if (distance < closest) {
1577 ret = r->first_frame();
1585 distance = end - frame;
1587 if (distance < closest) {
1601 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1603 boost::shared_ptr<Region> r = (*i);
1604 nframes64_t distance;
1609 if (r->last_frame() < frame) {
1611 distance = frame - r->last_frame();
1613 if (distance < closest) {
1614 ret = r->last_frame();
1620 if (r->first_frame() < frame) {
1621 distance = frame - r->last_frame();
1623 if (distance < closest) {
1624 ret = r->first_frame();
1639 /***********************************************************************/
1644 Playlist::mark_session_dirty ()
1646 if (!in_set_state && !holding_state ()) {
1647 _session.set_dirty();
1652 Playlist::set_state (const XMLNode& node)
1656 XMLNodeConstIterator niter;
1657 XMLPropertyList plist;
1658 XMLPropertyConstIterator piter;
1660 boost::shared_ptr<Region> region;
1665 if (node.name() != "Playlist") {
1672 plist = node.properties();
1674 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1678 if (prop->name() == X_("name")) {
1679 _name = prop->value();
1680 } else if (prop->name() == X_("orig_diskstream_id")) {
1681 _orig_diskstream_id = prop->value ();
1682 } else if (prop->name() == X_("frozen")) {
1683 _frozen = (prop->value() == X_("yes"));
1689 nlist = node.children();
1691 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1695 if (child->name() == "Region") {
1697 if ((prop = child->property ("id")) == 0) {
1698 error << _("region state node has no ID, ignored") << endmsg;
1702 ID id = prop->value ();
1704 if ((region = region_by_id (id))) {
1706 Change what_changed = Change (0);
1708 if (region->set_live_state (*child, what_changed, true)) {
1709 error << _("Playlist: cannot reset region state from XML") << endmsg;
1713 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1714 error << _("Playlist: cannot create region from XML") << endmsg;
1718 add_region (region, region->position(), 1.0);
1720 // So that layer_op ordering doesn't get screwed up
1721 region->set_last_layer_op( region->layer());
1730 /* update dependents, which was not done during add_region_internal
1731 due to in_set_state being true
1734 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1735 check_dependents (*r, false);
1739 first_set_state = false;
1744 Playlist::get_state()
1750 Playlist::get_template()
1752 return state(false);
1756 Playlist::state (bool full_state)
1758 XMLNode *node = new XMLNode (X_("Playlist"));
1761 node->add_property (X_("name"), _name);
1763 _orig_diskstream_id.print (buf, sizeof (buf));
1764 node->add_property (X_("orig_diskstream_id"), buf);
1765 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1768 RegionLock rlock (this, false);
1769 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1770 node->add_child_nocopy ((*i)->get_state());
1775 node->add_child_copy (*_extra_xml);
1782 Playlist::empty() const
1784 RegionLock rlock (const_cast<Playlist *>(this), false);
1785 return regions.empty();
1789 Playlist::n_regions() const
1791 RegionLock rlock (const_cast<Playlist *>(this), false);
1792 return regions.size();
1796 Playlist::get_maximum_extent () const
1798 RegionLock rlock (const_cast<Playlist *>(this), false);
1799 return _get_maximum_extent ();
1803 Playlist::_get_maximum_extent () const
1805 RegionList::const_iterator i;
1806 nframes_t max_extent = 0;
1809 for (i = regions.begin(); i != regions.end(); ++i) {
1810 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1819 Playlist::bump_name (string name, Session &session)
1821 string newname = name;
1824 newname = bump_name_once (newname);
1825 } while (session.playlist_by_name (newname)!=NULL);
1832 Playlist::top_layer() const
1834 RegionLock rlock (const_cast<Playlist *> (this));
1837 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1838 top = max (top, (*i)->layer());
1844 Playlist::set_edit_mode (EditMode mode)
1849 /********************
1851 ********************/
1854 Playlist::relayer ()
1856 RegionList::iterator i;
1859 /* don't send multiple Modified notifications
1860 when multiple regions are relayered.
1865 if (Config->get_layer_model() == MoveAddHigher ||
1866 Config->get_layer_model() == AddHigher) {
1868 RegionSortByLastLayerOp cmp;
1869 RegionList copy = regions;
1873 for (i = copy.begin(); i != copy.end(); ++i) {
1874 (*i)->set_layer (layer++);
1879 /* Session::LaterHigher model */
1881 for (i = regions.begin(); i != regions.end(); ++i) {
1882 (*i)->set_layer (layer++);
1886 /* sending Modified means that various kinds of layering
1887 models operate correctly at the GUI
1888 level. slightly inefficient, but only slightly.
1890 We force a Modified signal here in case no layers actually
1899 /* XXX these layer functions are all deprecated */
1902 Playlist::raise_region (boost::shared_ptr<Region> region)
1904 uint32_t rsz = regions.size();
1905 layer_t target = region->layer() + 1U;
1907 if (target >= rsz) {
1908 /* its already at the effective top */
1912 move_region_to_layer (target, region, 1);
1916 Playlist::lower_region (boost::shared_ptr<Region> region)
1918 if (region->layer() == 0) {
1919 /* its already at the bottom */
1923 layer_t target = region->layer() - 1U;
1925 move_region_to_layer (target, region, -1);
1929 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
1931 /* does nothing useful if layering mode is later=higher */
1932 if ((Config->get_layer_model() == MoveAddHigher) ||
1933 (Config->get_layer_model() == AddHigher)) {
1934 timestamp_layer_op (region);
1940 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
1942 /* does nothing useful if layering mode is later=higher */
1943 if ((Config->get_layer_model() == MoveAddHigher) ||
1944 (Config->get_layer_model() == AddHigher)) {
1945 region->set_last_layer_op (0);
1951 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
1953 RegionList::iterator i;
1954 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
1955 list<LayerInfo> layerinfo;
1959 RegionLock rlock (const_cast<Playlist *> (this));
1961 for (i = regions.begin(); i != regions.end(); ++i) {
1969 /* region is moving up, move all regions on intermediate layers
1973 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
1974 dest = (*i)->layer() - 1;
1981 /* region is moving down, move all regions on intermediate layers
1985 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
1986 dest = (*i)->layer() + 1;
1996 newpair.second = dest;
1998 layerinfo.push_back (newpair);
2002 /* now reset the layers without holding the region lock */
2004 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2005 x->first->set_layer (x->second);
2008 region->set_layer (target_layer);
2011 /* now check all dependents */
2013 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2014 check_dependents (x->first, false);
2017 check_dependents (region, false);
2024 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2026 RegionList::iterator i;
2033 RegionLock rlock (const_cast<Playlist *> (this));
2035 for (i = regions.begin(); i != regions.end(); ++i) {
2037 if ((*i)->position() >= start) {
2041 if ((*i)->last_frame() > max_frames - distance) {
2042 new_pos = max_frames - (*i)->length();
2044 new_pos = (*i)->position() + distance;
2049 if ((*i)->position() > distance) {
2050 new_pos = (*i)->position() - distance;
2056 (*i)->set_position (new_pos, this);
2064 notify_length_changed ();
2069 boost::shared_ptr<Region>
2070 Playlist::find_region (const ID& id) const
2072 RegionLock rlock (const_cast<Playlist*> (this));
2074 /* searches all regions currently in use by the playlist */
2076 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2077 if ((*i)->id() == id) {
2082 return boost::shared_ptr<Region> ();
2085 boost::shared_ptr<Region>
2086 Playlist::region_by_id (ID id)
2088 /* searches all regions ever added to this playlist */
2090 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2091 if ((*i)->id() == id) {
2095 return boost::shared_ptr<Region> ();
2099 Playlist::dump () const
2101 boost::shared_ptr<Region> r;
2103 cerr << "Playlist \"" << _name << "\" " << endl
2104 << regions.size() << " regions "
2107 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2109 cerr << " " << r->name() << " ["
2110 << r->start() << "+" << r->length()
2120 Playlist::set_frozen (bool yn)
2126 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2128 // struct timeval tv;
2129 // gettimeofday (&tv, 0);
2130 region->set_last_layer_op (++layer_op_counter);
2135 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2140 if (region->locked()) {
2147 RegionLock rlock (const_cast<Playlist*> (this));
2152 RegionList::iterator next;
2154 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2155 if ((*i) == region) {
2159 if (next != regions.end()) {
2161 if ((*next)->locked()) {
2165 if ((*next)->position() != region->last_frame() + 1) {
2166 /* they didn't used to touch, so after shuffle,
2167 just have them swap positions.
2169 new_pos = (*next)->position();
2171 /* they used to touch, so after shuffle,
2172 make sure they still do. put the earlier
2173 region where the later one will end after
2176 new_pos = region->position() + (*next)->length();
2179 (*next)->set_position (region->position(), this);
2180 region->set_position (new_pos, this);
2182 /* avoid a full sort */
2184 regions.erase (i); // removes the region from the list */
2186 regions.insert (next, region); // adds it back after next
2195 RegionList::iterator prev = regions.end();
2197 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2198 if ((*i) == region) {
2200 if (prev != regions.end()) {
2202 if ((*prev)->locked()) {
2206 if (region->position() != (*prev)->last_frame() + 1) {
2207 /* they didn't used to touch, so after shuffle,
2208 just have them swap positions.
2210 new_pos = region->position();
2212 /* they used to touch, so after shuffle,
2213 make sure they still do. put the earlier
2214 one where the later one will end after
2216 new_pos = (*prev)->position() + region->length();
2219 region->set_position ((*prev)->position(), this);
2220 (*prev)->set_position (new_pos, this);
2222 /* avoid a full sort */
2224 regions.erase (i); // remove region
2225 regions.insert (prev, region); // insert region before prev
2241 check_dependents (region, false);
2249 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2251 RegionLock rlock (const_cast<Playlist*> (this));
2253 if (regions.size() > 1) {
2261 Playlist::update_after_tempo_map_change ()
2263 RegionLock rlock (const_cast<Playlist*> (this));
2264 RegionList copy (regions);
2268 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2269 (*i)->update_position_after_tempo_map_change ();