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>
44 using namespace ARDOUR;
47 struct ShowMeTheList {
48 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
50 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
52 boost::shared_ptr<Playlist> playlist;
56 struct RegionSortByLayer {
57 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
58 return a->layer() < b->layer();
62 struct RegionSortByPosition {
63 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
64 return a->position() < b->position();
68 struct RegionSortByLastLayerOp {
69 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
70 return a->last_layer_op() < b->last_layer_op();
74 Playlist::Playlist (Session& sess, string nom, bool hide)
78 first_set_state = false;
83 Playlist::Playlist (Session& sess, const XMLNode& node, bool hide)
87 _name = "unnamed"; /* reset by set_state */
89 /* set state called by derived class */
92 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
93 : _name (namestr), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
98 other->copy_regions (tmp);
102 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
103 add_region_internal( (*x), (*x)->position());
108 _splicing = other->_splicing;
109 _nudging = other->_nudging;
110 _edit_mode = other->_edit_mode;
113 first_set_state = false;
115 in_partition = false;
117 _read_data_count = 0;
118 _frozen = other->_frozen;
120 layer_op_counter = other->layer_op_counter;
121 freeze_length = other->freeze_length;
124 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
125 : _name (str), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
127 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
129 nframes_t end = start + cnt - 1;
135 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
137 boost::shared_ptr<Region> region;
138 boost::shared_ptr<Region> new_region;
139 nframes_t offset = 0;
140 nframes_t position = 0;
147 overlap = region->coverage (start, end);
153 case OverlapInternal:
154 offset = start - region->position();
161 position = region->position() - start;
162 len = end - region->position();
166 offset = start - region->position();
168 len = region->length() - offset;
171 case OverlapExternal:
173 position = region->position() - start;
174 len = region->length();
178 _session.region_name (new_name, region->name(), false);
180 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
182 add_region_internal (new_region, position);
186 first_set_state = false;
188 /* this constructor does NOT notify others (session) */
195 InUse (true); /* EMIT SIGNAL */
206 InUse (false); /* EMIT SIGNAL */
211 Playlist::copy_regions (RegionList& newlist) const
213 RegionLock rlock (const_cast<Playlist *> (this));
215 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
216 newlist.push_back (RegionFactory::RegionFactory::create (*i));
221 Playlist::init (bool hide)
223 g_atomic_int_set (&block_notifications, 0);
224 g_atomic_int_set (&ignore_state_changes, 0);
225 pending_modified = false;
226 pending_length = false;
227 first_set_state = true;
234 _edit_mode = Config->get_edit_mode();
236 in_partition = false;
238 _read_data_count = 0;
240 layer_op_counter = 0;
243 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
246 Playlist::Playlist (const Playlist& pl)
247 : _session (pl._session)
249 fatal << _("playlist const copy constructor called") << endmsg;
252 Playlist::Playlist (Playlist& pl)
253 : _session (pl._session)
255 fatal << _("playlist non-const copy constructor called") << endmsg;
258 Playlist::~Playlist ()
261 RegionLock rl (this);
263 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
264 (*i)->set_playlist (boost::shared_ptr<Playlist>());
268 /* GoingAway must be emitted by derived classes */
272 Playlist::set_name (string str)
274 /* in a typical situation, a playlist is being used
275 by one diskstream and also is referenced by the
276 Session. if there are more references than that,
277 then don't change the name.
285 NameChanged(); /* EMIT SIGNAL */
288 /***********************************************************************
289 CHANGE NOTIFICATION HANDLING
291 Notifications must be delayed till the region_lock is released. This
292 is necessary because handlers for the signals may need to acquire
293 the lock (e.g. to read from the playlist).
294 ***********************************************************************/
299 delay_notifications ();
300 g_atomic_int_inc (&ignore_state_changes);
306 g_atomic_int_dec_and_test (&ignore_state_changes);
307 release_notifications ();
312 Playlist::delay_notifications ()
314 g_atomic_int_inc (&block_notifications);
315 freeze_length = _get_maximum_extent();
319 Playlist::release_notifications ()
321 if (g_atomic_int_dec_and_test (&block_notifications)) {
322 flush_notifications ();
328 Playlist::notify_modified ()
330 if (holding_state ()) {
331 pending_modified = true;
333 pending_modified = false;
334 Modified(); /* EMIT SIGNAL */
339 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
341 if (holding_state ()) {
342 pending_removes.insert (r);
343 pending_modified = true;
344 pending_length = true;
346 /* this might not be true, but we have to act
347 as though it could be.
349 LengthChanged (); /* EMIT SIGNAL */
350 Modified (); /* EMIT SIGNAL */
355 Playlist::notify_region_added (boost::shared_ptr<Region> r)
357 /* the length change might not be true, but we have to act
358 as though it could be.
361 if (holding_state()) {
362 pending_adds.insert (r);
363 pending_modified = true;
364 pending_length = true;
366 LengthChanged (); /* EMIT SIGNAL */
367 Modified (); /* EMIT SIGNAL */
372 Playlist::notify_length_changed ()
374 if (holding_state ()) {
375 pending_length = true;
377 LengthChanged(); /* EMIT SIGNAL */
378 Modified (); /* EMIT SIGNAL */
383 Playlist::flush_notifications ()
385 set<boost::shared_ptr<Region> > dependent_checks_needed;
386 set<boost::shared_ptr<Region> >::iterator s;
395 /* we have no idea what order the regions ended up in pending
396 bounds (it could be based on selection order, for example).
397 so, to preserve layering in the "most recently moved is higher"
398 model, sort them by existing layer, then timestamp them.
401 // RegionSortByLayer cmp;
402 // pending_bounds.sort (cmp);
404 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
405 if (Config->get_layer_model() == MoveAddHigher) {
406 timestamp_layer_op (*r);
408 pending_length = true;
409 dependent_checks_needed.insert (*r);
413 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
414 dependent_checks_needed.insert (*s);
418 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
419 remove_dependents (*s);
423 if ((freeze_length != _get_maximum_extent()) || pending_length) {
425 LengthChanged(); /* EMIT SIGNAL */
429 if (n || pending_modified) {
433 pending_modified = false;
434 Modified (); /* EMIT SIGNAL */
437 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
438 check_dependents (*s, false);
441 pending_adds.clear ();
442 pending_removes.clear ();
443 pending_bounds.clear ();
448 /*************************************************************
450 *************************************************************/
453 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
455 RegionLock rlock (this);
457 times = fabs (times);
459 int itimes = (int) floor (times);
461 nframes_t pos = position;
464 add_region_internal (region, pos);
465 pos += region->length();
470 /* note that itimes can be zero if we being asked to just
471 insert a single fraction of the region.
474 for (int i = 0; i < itimes; ++i) {
475 boost::shared_ptr<Region> copy = RegionFactory::create (region);
476 add_region_internal (copy, pos);
477 pos += region->length();
480 nframes_t length = 0;
482 if (floor (times) != times) {
483 length = (nframes_t) floor (region->length() * (times - floor (times)));
485 _session.region_name (name, region->name(), false);
486 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
487 add_region_internal (sub, pos);
491 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
495 Playlist::set_region_ownership ()
497 RegionLock rl (this);
498 RegionList::iterator i;
499 boost::weak_ptr<Playlist> pl (shared_from_this());
501 for (i = regions.begin(); i != regions.end(); ++i) {
502 (*i)->set_playlist (pl);
507 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
509 RegionSortByPosition cmp;
510 nframes_t old_length = 0;
512 if (!holding_state()) {
513 old_length = _get_maximum_extent();
516 if (!first_set_state) {
517 boost::shared_ptr<Playlist> foo (shared_from_this());
518 region->set_playlist (boost::weak_ptr<Playlist>(foo));
521 region->set_position (position, this);
523 timestamp_layer_op (region);
525 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
526 all_regions.insert (region);
528 possibly_splice_unlocked (position, region->length(), region);
530 if (!holding_state () && !in_set_state) {
531 /* layers get assigned from XML state */
535 /* we need to notify the existence of new region before checking dependents. Ick. */
537 notify_region_added (region);
539 if (!holding_state ()) {
540 check_dependents (region, false);
541 if (old_length != _get_maximum_extent()) {
542 notify_length_changed ();
546 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
547 boost::weak_ptr<Region> (region)));
551 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
553 RegionLock rlock (this);
555 bool old_sp = _splicing;
558 remove_region_internal (old);
559 add_region_internal (newr, pos);
563 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
567 Playlist::remove_region (boost::shared_ptr<Region> region)
569 RegionLock rlock (this);
570 remove_region_internal (region);
574 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
576 RegionList::iterator i;
577 nframes_t old_length = 0;
579 if (!holding_state()) {
580 old_length = _get_maximum_extent();
585 region->set_playlist (boost::weak_ptr<Playlist>());
588 for (i = regions.begin(); i != regions.end(); ++i) {
591 nframes_t pos = (*i)->position();
592 nframes64_t distance = (*i)->length();
596 possibly_splice_unlocked (pos, -distance);
598 if (!holding_state ()) {
600 remove_dependents (region);
602 if (old_length != _get_maximum_extent()) {
603 notify_length_changed ();
607 notify_region_removed (region);
618 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
620 if (Config->get_use_overlap_equivalency()) {
621 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
622 if ((*i)->overlap_equivalent (other)) {
623 results.push_back ((*i));
627 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
628 if ((*i)->equivalent (other)) {
629 results.push_back ((*i));
636 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
638 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
640 if ((*i) && (*i)->region_list_equivalent (other)) {
641 results.push_back (*i);
647 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
651 partition_internal (start, end, false, thawlist);
653 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
654 (*i)->thaw ("separation");
659 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
661 RegionLock rlock (this);
662 boost::shared_ptr<Region> region;
663 boost::shared_ptr<Region> current;
665 RegionList::iterator tmp;
667 nframes_t pos1, pos2, pos3, pos4;
668 RegionList new_regions;
672 /* need to work from a copy, because otherwise the regions we add during the process
673 get operated on as well.
676 RegionList copy = regions;
678 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
685 if (current->first_frame() == start && current->last_frame() == end) {
687 remove_region_internal (current);
692 if ((overlap = current->coverage (start, end)) == OverlapNone) {
696 pos1 = current->position();
699 pos4 = current->last_frame();
701 if (overlap == OverlapInternal) {
703 /* split: we need 3 new regions, the front, middle and end.
704 cut: we need 2 regions, the front and end.
709 ---------------*************************------------
712 ---------------*****++++++++++++++++====------------
714 ---------------*****----------------====------------
720 /* "middle" ++++++ */
722 _session.region_name (new_name, current->name(), false);
723 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
724 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
725 add_region_internal (region, start);
726 new_regions.push_back (region);
731 _session.region_name (new_name, current->name(), false);
732 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
733 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
735 add_region_internal (region, end);
736 new_regions.push_back (region);
741 thawlist.push_back (current);
742 current->trim_end (pos2, this);
744 } else if (overlap == OverlapEnd) {
748 ---------------*************************------------
751 ---------------**************+++++++++++------------
753 ---------------**************-----------------------
761 _session.region_name (new_name, current->name(), false);
762 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
763 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
764 add_region_internal (region, start);
765 new_regions.push_back (region);
771 thawlist.push_back (current);
772 current->trim_end (pos2, this);
774 } else if (overlap == OverlapStart) {
776 /* split: we need 2 regions: the front and the end.
777 cut: just trim current to skip the cut area
782 ---------------*************************------------
786 ---------------****+++++++++++++++++++++------------
788 -------------------*********************------------
795 _session.region_name (new_name, current->name(), false);
796 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
797 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
798 add_region_internal (region, pos1);
799 new_regions.push_back (region);
805 thawlist.push_back (current);
806 current->trim_front (pos3, this);
808 } else if (overlap == OverlapExternal) {
810 /* split: no split required.
811 cut: remove the region.
816 ---------------*************************------------
820 ---------------*************************------------
822 ----------------------------------------------------
827 remove_region_internal (current);
829 new_regions.push_back (current);
833 in_partition = false;
835 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
836 check_dependents (*i, false);
840 boost::shared_ptr<Playlist>
841 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
843 boost::shared_ptr<Playlist> ret;
844 boost::shared_ptr<Playlist> pl;
847 if (ranges.empty()) {
848 return boost::shared_ptr<Playlist>();
851 start = ranges.front().start;
853 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
855 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
857 if (i == ranges.begin()) {
861 /* paste the next section into the nascent playlist,
862 offset to reflect the start of the first range we
866 ret->paste (pl, (*i).start - start, 1.0f);
873 boost::shared_ptr<Playlist>
874 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
876 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
877 return cut_copy (pmf, ranges, result_is_hidden);
880 boost::shared_ptr<Playlist>
881 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
883 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
884 return cut_copy (pmf, ranges, result_is_hidden);
887 boost::shared_ptr<Playlist>
888 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
890 boost::shared_ptr<Playlist> the_copy;
894 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
895 string new_name = _name;
899 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
900 return boost::shared_ptr<Playlist>();
903 partition_internal (start, start+cnt-1, true, thawlist);
905 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
906 (*i)->thaw ("playlist cut");
912 boost::shared_ptr<Playlist>
913 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
917 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
918 string new_name = _name;
922 cnt = min (_get_maximum_extent() - start, cnt);
923 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
927 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
929 times = fabs (times);
930 nframes_t old_length;
933 RegionLock rl1 (this);
934 RegionLock rl2 (other.get());
936 old_length = _get_maximum_extent();
938 int itimes = (int) floor (times);
939 nframes_t pos = position;
940 nframes_t shift = other->_get_maximum_extent();
941 layer_t top_layer = regions.size();
944 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
945 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
947 /* put these new regions on top of all existing ones, but preserve
948 the ordering they had in the original playlist.
951 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
952 add_region_internal (copy_of_region, copy_of_region->position() + pos);
958 /* XXX shall we handle fractional cases at some point? */
960 if (old_length != _get_maximum_extent()) {
961 notify_length_changed ();
972 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
974 times = fabs (times);
976 RegionLock rl (this);
977 int itimes = (int) floor (times);
978 nframes_t pos = position;
981 boost::shared_ptr<Region> copy = RegionFactory::create (region);
982 add_region_internal (copy, pos);
983 pos += region->length();
986 if (floor (times) != times) {
987 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
989 _session.region_name (name, region->name(), false);
990 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
991 add_region_internal (sub, pos);
996 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
998 RegionLock rl (this);
1000 if (!region->covers (playlist_position)) {
1004 if (region->position() == playlist_position ||
1005 region->last_frame() == playlist_position) {
1009 boost::shared_ptr<Region> left;
1010 boost::shared_ptr<Region> right;
1016 /* split doesn't change anything about length, so don't try to splice */
1018 bool old_sp = _splicing;
1021 before = playlist_position - region->position();
1022 after = region->length() - before;
1024 _session.region_name (before_name, region->name(), false);
1025 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1027 _session.region_name (after_name, region->name(), false);
1028 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1030 add_region_internal (left, region->position());
1031 add_region_internal (right, region->position() + before);
1033 uint64_t orig_layer_op = region->last_layer_op();
1034 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1035 if ((*i)->last_layer_op() > orig_layer_op) {
1036 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1040 left->set_last_layer_op ( orig_layer_op );
1041 right->set_last_layer_op ( orig_layer_op + 1);
1045 finalize_split_region (region, left, right);
1047 remove_region_internal (region);
1053 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1055 if (_splicing || in_set_state) {
1056 /* don't respond to splicing moves or state setting */
1060 if (_edit_mode == Splice) {
1061 splice_locked (at, distance, exclude);
1066 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1068 if (_splicing || in_set_state) {
1069 /* don't respond to splicing moves or state setting */
1073 if (_edit_mode == Splice) {
1074 splice_unlocked (at, distance, exclude);
1079 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1082 RegionLock rl (this);
1083 core_splice (at, distance, exclude);
1088 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1090 core_splice (at, distance, exclude);
1094 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1098 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1100 if (exclude && (*i) == exclude) {
1104 if ((*i)->position() >= at) {
1105 nframes64_t new_pos = (*i)->position() + distance;
1108 } else if (new_pos >= max_frames - (*i)->length()) {
1109 new_pos = max_frames - (*i)->length();
1112 (*i)->set_position (new_pos, this);
1118 notify_length_changed ();
1122 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1124 if (in_set_state || _splicing || _nudging || _shuffling) {
1128 if (what_changed & ARDOUR::PositionChanged) {
1130 /* remove it from the list then add it back in
1131 the right place again.
1134 RegionSortByPosition cmp;
1136 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1138 if (i == regions.end()) {
1139 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1140 _name, region->name())
1146 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1149 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1151 nframes64_t delta = 0;
1153 if (what_changed & ARDOUR::PositionChanged) {
1154 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1157 if (what_changed & ARDOUR::LengthChanged) {
1158 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1162 possibly_splice (region->last_position() + region->last_length(), delta, region);
1165 if (holding_state ()) {
1166 pending_bounds.push_back (region);
1168 if (Config->get_layer_model() == MoveAddHigher) {
1169 /* it moved or changed length, so change the timestamp */
1170 timestamp_layer_op (region);
1173 notify_length_changed ();
1175 check_dependents (region, false);
1181 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1183 boost::shared_ptr<Region> region (weak_region.lock());
1190 /* this makes a virtual call to the right kind of playlist ... */
1192 region_changed (what_changed, region);
1196 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1198 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1201 if (in_set_state || in_flush) {
1206 if (what_changed & BoundsChanged) {
1207 region_bounds_changed (what_changed, region);
1208 save = !(_splicing || _nudging);
1211 if ((what_changed & our_interests) &&
1212 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1213 check_dependents (region, false);
1216 if (what_changed & our_interests) {
1225 Playlist::drop_regions ()
1227 RegionLock rl (this);
1229 all_regions.clear ();
1233 Playlist::clear (bool with_signals)
1236 RegionLock rl (this);
1237 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1238 pending_removes.insert (*i);
1250 /***********************************************************************
1252 **********************************************************************/
1254 Playlist::RegionList *
1255 Playlist::regions_at (nframes_t frame)
1258 RegionLock rlock (this);
1259 return find_regions_at (frame);
1262 boost::shared_ptr<Region>
1263 Playlist::top_region_at (nframes_t frame)
1266 RegionLock rlock (this);
1267 RegionList *rlist = find_regions_at (frame);
1268 boost::shared_ptr<Region> region;
1270 if (rlist->size()) {
1271 RegionSortByLayer cmp;
1273 region = rlist->back();
1280 Playlist::RegionList*
1281 Playlist::regions_to_read (nframes_t start, nframes_t end)
1283 /* Caller must hold lock */
1285 RegionList covering;
1286 set<nframes_t> to_check;
1287 set<boost::shared_ptr<Region> > unique;
1290 to_check.insert (start);
1291 to_check.insert (end);
1293 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1295 /* find all/any regions that span start+end */
1297 switch ((*i)->coverage (start, end)) {
1301 case OverlapInternal:
1302 covering.push_back (*i);
1306 to_check.insert ((*i)->position());
1307 covering.push_back (*i);
1311 to_check.insert ((*i)->last_frame());
1312 covering.push_back (*i);
1315 case OverlapExternal:
1316 covering.push_back (*i);
1317 to_check.insert ((*i)->position());
1318 to_check.insert ((*i)->last_frame());
1322 /* don't go too far */
1324 if ((*i)->position() > end) {
1329 RegionList* rlist = new RegionList;
1331 /* find all the regions that cover each position .... */
1333 if (covering.size() == 1) {
1335 rlist->push_back (covering.front());
1339 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1343 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1345 if ((*x)->covers (*t)) {
1346 here.push_back (*x);
1350 RegionSortByLayer cmp;
1353 /* ... and get the top/transparent regions at "here" */
1355 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1359 if ((*c)->opaque()) {
1361 /* the other regions at this position are hidden by this one */
1368 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1369 rlist->push_back (*s);
1372 if (rlist->size() > 1) {
1373 /* now sort by time order */
1375 RegionSortByPosition cmp;
1383 Playlist::RegionList *
1384 Playlist::find_regions_at (nframes_t frame)
1386 /* Caller must hold lock */
1388 RegionList *rlist = new RegionList;
1390 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1391 if ((*i)->covers (frame)) {
1392 rlist->push_back (*i);
1399 Playlist::RegionList *
1400 Playlist::regions_touched (nframes_t start, nframes_t end)
1402 RegionLock rlock (this);
1403 RegionList *rlist = new RegionList;
1405 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1406 if ((*i)->coverage (start, end) != OverlapNone) {
1407 rlist->push_back (*i);
1415 boost::shared_ptr<Region>
1416 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1418 RegionLock rlock (this);
1419 boost::shared_ptr<Region> ret;
1420 nframes_t closest = max_frames;
1423 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1426 boost::shared_ptr<Region> r = (*i);
1431 pos = r->first_frame ();
1434 pos = r->last_frame ();
1437 pos = r->adjust_to_sync (r->first_frame());
1442 case 1: /* forwards */
1445 if ((distance = pos - frame) < closest) {
1453 default: /* backwards */
1456 if ((distance = frame - pos) < closest) {
1469 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1471 RegionLock rlock (this);
1473 nframes64_t closest = max_frames;
1474 nframes64_t ret = -1;
1478 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1480 boost::shared_ptr<Region> r = (*i);
1481 nframes64_t distance;
1482 nframes64_t end = r->position() + r->length();
1487 if (r->first_frame() > frame) {
1489 distance = r->first_frame() - frame;
1491 if (distance < closest) {
1492 ret = r->first_frame();
1500 distance = end - frame;
1502 if (distance < closest) {
1516 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1518 boost::shared_ptr<Region> r = (*i);
1519 nframes64_t distance;
1524 if (r->last_frame() < frame) {
1526 distance = frame - r->last_frame();
1528 if (distance < closest) {
1529 ret = r->last_frame();
1535 if (r->first_frame() < frame) {
1536 distance = frame - r->last_frame();
1538 if (distance < closest) {
1539 ret = r->first_frame();
1554 /***********************************************************************/
1559 Playlist::mark_session_dirty ()
1561 if (!in_set_state && !holding_state ()) {
1562 _session.set_dirty();
1567 Playlist::set_state (const XMLNode& node)
1571 XMLNodeConstIterator niter;
1572 XMLPropertyList plist;
1573 XMLPropertyConstIterator piter;
1575 boost::shared_ptr<Region> region;
1580 if (node.name() != "Playlist") {
1587 plist = node.properties();
1589 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1593 if (prop->name() == X_("name")) {
1594 _name = prop->value();
1595 } else if (prop->name() == X_("orig_diskstream_id")) {
1596 _orig_diskstream_id = prop->value ();
1597 } else if (prop->name() == X_("frozen")) {
1598 _frozen = (prop->value() == X_("yes"));
1604 nlist = node.children();
1606 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1610 if (child->name() == "Region") {
1612 if ((prop = child->property ("id")) == 0) {
1613 error << _("region state node has no ID, ignored") << endmsg;
1617 ID id = prop->value ();
1619 if ((region = region_by_id (id))) {
1621 Change what_changed = Change (0);
1623 if (region->set_live_state (*child, what_changed, true)) {
1624 error << _("Playlist: cannot reset region state from XML") << endmsg;
1628 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1629 error << _("Playlist: cannot create region from XML") << endmsg;
1633 add_region (region, region->position(), 1.0);
1635 // So that layer_op ordering doesn't get screwed up
1636 region->set_last_layer_op( region->layer());
1645 /* update dependents, which was not done during add_region_internal
1646 due to in_set_state being true
1649 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1650 check_dependents (*r, false);
1654 first_set_state = false;
1659 Playlist::get_state()
1665 Playlist::get_template()
1667 return state(false);
1671 Playlist::state (bool full_state)
1673 XMLNode *node = new XMLNode (X_("Playlist"));
1676 node->add_property (X_("name"), _name);
1678 _orig_diskstream_id.print (buf, sizeof (buf));
1679 node->add_property (X_("orig_diskstream_id"), buf);
1680 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1683 RegionLock rlock (this, false);
1684 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1685 node->add_child_nocopy ((*i)->get_state());
1690 node->add_child_copy (*_extra_xml);
1697 Playlist::empty() const
1699 RegionLock rlock (const_cast<Playlist *>(this), false);
1700 return regions.empty();
1704 Playlist::n_regions() const
1706 RegionLock rlock (const_cast<Playlist *>(this), false);
1707 return regions.size();
1711 Playlist::get_maximum_extent () const
1713 RegionLock rlock (const_cast<Playlist *>(this), false);
1714 return _get_maximum_extent ();
1718 Playlist::_get_maximum_extent () const
1720 RegionList::const_iterator i;
1721 nframes_t max_extent = 0;
1724 for (i = regions.begin(); i != regions.end(); ++i) {
1725 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1734 Playlist::bump_name (string name, Session &session)
1736 string newname = name;
1739 newname = Playlist::bump_name_once (newname);
1740 } while (session.playlist_by_name (newname)!=NULL);
1746 Playlist::bump_name_once (string name)
1748 string::size_type period;
1751 if ((period = name.find_last_of ('.')) == string::npos) {
1756 const char *last_element = name.c_str() + period + 1;
1757 for (size_t i = 0; i < strlen(last_element); i++) {
1758 if (!isdigit(last_element[i])) {
1765 long int version = strtol (name.c_str()+period+1, (char **)NULL, 10);
1767 if (isnumber == 0 || errno != 0) {
1768 // last_element is not a number, or is too large
1774 snprintf (buf, sizeof(buf), "%ld", version+1);
1776 newname = name.substr (0, period+1);
1785 Playlist::top_layer() const
1787 RegionLock rlock (const_cast<Playlist *> (this));
1790 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1791 top = max (top, (*i)->layer());
1797 Playlist::set_edit_mode (EditMode mode)
1802 /********************
1804 ********************/
1807 Playlist::relayer ()
1809 RegionList::iterator i;
1812 /* don't send multiple Modified notifications
1813 when multiple regions are relayered.
1818 if (Config->get_layer_model() == MoveAddHigher ||
1819 Config->get_layer_model() == AddHigher) {
1821 RegionSortByLastLayerOp cmp;
1822 RegionList copy = regions;
1826 for (i = copy.begin(); i != copy.end(); ++i) {
1827 (*i)->set_layer (layer++);
1832 /* Session::LaterHigher model */
1834 for (i = regions.begin(); i != regions.end(); ++i) {
1835 (*i)->set_layer (layer++);
1839 /* sending Modified means that various kinds of layering
1840 models operate correctly at the GUI
1841 level. slightly inefficient, but only slightly.
1843 We force a Modified signal here in case no layers actually
1852 /* XXX these layer functions are all deprecated */
1855 Playlist::raise_region (boost::shared_ptr<Region> region)
1857 uint32_t rsz = regions.size();
1858 layer_t target = region->layer() + 1U;
1860 if (target >= rsz) {
1861 /* its already at the effective top */
1865 move_region_to_layer (target, region, 1);
1869 Playlist::lower_region (boost::shared_ptr<Region> region)
1871 if (region->layer() == 0) {
1872 /* its already at the bottom */
1876 layer_t target = region->layer() - 1U;
1878 move_region_to_layer (target, region, -1);
1882 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
1884 /* does nothing useful if layering mode is later=higher */
1885 if ((Config->get_layer_model() == MoveAddHigher) ||
1886 (Config->get_layer_model() == AddHigher)) {
1887 timestamp_layer_op (region);
1893 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
1895 /* does nothing useful if layering mode is later=higher */
1896 if ((Config->get_layer_model() == MoveAddHigher) ||
1897 (Config->get_layer_model() == AddHigher)) {
1898 region->set_last_layer_op (0);
1904 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
1906 RegionList::iterator i;
1907 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
1908 list<LayerInfo> layerinfo;
1912 RegionLock rlock (const_cast<Playlist *> (this));
1914 for (i = regions.begin(); i != regions.end(); ++i) {
1922 /* region is moving up, move all regions on intermediate layers
1926 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
1927 dest = (*i)->layer() - 1;
1934 /* region is moving down, move all regions on intermediate layers
1938 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
1939 dest = (*i)->layer() + 1;
1949 newpair.second = dest;
1951 layerinfo.push_back (newpair);
1955 /* now reset the layers without holding the region lock */
1957 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1958 x->first->set_layer (x->second);
1961 region->set_layer (target_layer);
1964 /* now check all dependents */
1966 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1967 check_dependents (x->first, false);
1970 check_dependents (region, false);
1977 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
1979 RegionList::iterator i;
1986 RegionLock rlock (const_cast<Playlist *> (this));
1988 for (i = regions.begin(); i != regions.end(); ++i) {
1990 if ((*i)->position() >= start) {
1994 if ((*i)->last_frame() > max_frames - distance) {
1995 new_pos = max_frames - (*i)->length();
1997 new_pos = (*i)->position() + distance;
2002 if ((*i)->position() > distance) {
2003 new_pos = (*i)->position() - distance;
2009 (*i)->set_position (new_pos, this);
2017 notify_length_changed ();
2022 boost::shared_ptr<Region>
2023 Playlist::find_region (const ID& id) const
2025 RegionLock rlock (const_cast<Playlist*> (this));
2027 /* searches all regions currently in use by the playlist */
2029 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2030 if ((*i)->id() == id) {
2035 return boost::shared_ptr<Region> ();
2038 boost::shared_ptr<Region>
2039 Playlist::region_by_id (ID id)
2041 /* searches all regions ever added to this playlist */
2043 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2044 if ((*i)->id() == id) {
2048 return boost::shared_ptr<Region> ();
2052 Playlist::dump () const
2054 boost::shared_ptr<Region> r;
2056 cerr << "Playlist \"" << _name << "\" " << endl
2057 << regions.size() << " regions "
2060 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2062 cerr << " " << r->name() << " ["
2063 << r->start() << "+" << r->length()
2073 Playlist::set_frozen (bool yn)
2079 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2081 // struct timeval tv;
2082 // gettimeofday (&tv, 0);
2083 region->set_last_layer_op (++layer_op_counter);
2088 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2093 if (region->locked()) {
2100 RegionLock rlock (const_cast<Playlist*> (this));
2105 RegionList::iterator next;
2107 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2108 if ((*i) == region) {
2112 if (next != regions.end()) {
2114 if ((*next)->locked()) {
2118 if ((*next)->position() != region->last_frame() + 1) {
2119 /* they didn't used to touch, so after shuffle,
2120 just have them swap positions.
2122 new_pos = (*next)->position();
2124 /* they used to touch, so after shuffle,
2125 make sure they still do. put the earlier
2126 region where the later one will end after
2129 new_pos = region->position() + (*next)->length();
2132 (*next)->set_position (region->position(), this);
2133 region->set_position (new_pos, this);
2135 /* avoid a full sort */
2137 regions.erase (i); // removes the region from the list */
2139 regions.insert (next, region); // adds it back after next
2148 RegionList::iterator prev = regions.end();
2150 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2151 if ((*i) == region) {
2153 if (prev != regions.end()) {
2155 if ((*prev)->locked()) {
2159 if (region->position() != (*prev)->last_frame() + 1) {
2160 /* they didn't used to touch, so after shuffle,
2161 just have them swap positions.
2163 new_pos = region->position();
2165 /* they used to touch, so after shuffle,
2166 make sure they still do. put the earlier
2167 one where the later one will end after
2169 new_pos = (*prev)->position() + region->length();
2172 region->set_position ((*prev)->position(), this);
2173 (*prev)->set_position (new_pos, this);
2175 /* avoid a full sort */
2177 regions.erase (i); // remove region
2178 regions.insert (prev, region); // insert region before prev
2194 check_dependents (region, false);
2202 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2204 RegionLock rlock (const_cast<Playlist*> (this));
2206 if (regions.size() > 1) {