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;
233 _edit_mode = Config->get_edit_mode();
235 in_partition = false;
237 _read_data_count = 0;
239 layer_op_counter = 0;
242 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
245 Playlist::Playlist (const Playlist& pl)
246 : _session (pl._session)
248 fatal << _("playlist const copy constructor called") << endmsg;
251 Playlist::Playlist (Playlist& pl)
252 : _session (pl._session)
254 fatal << _("playlist non-const copy constructor called") << endmsg;
257 Playlist::~Playlist ()
260 RegionLock rl (this);
262 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
263 (*i)->set_playlist (boost::shared_ptr<Playlist>());
267 /* GoingAway must be emitted by derived classes */
271 Playlist::set_name (string str)
273 /* in a typical situation, a playlist is being used
274 by one diskstream and also is referenced by the
275 Session. if there are more references than that,
276 then don't change the name.
284 NameChanged(); /* EMIT SIGNAL */
287 /***********************************************************************
288 CHANGE NOTIFICATION HANDLING
290 Notifications must be delayed till the region_lock is released. This
291 is necessary because handlers for the signals may need to acquire
292 the lock (e.g. to read from the playlist).
293 ***********************************************************************/
298 delay_notifications ();
299 g_atomic_int_inc (&ignore_state_changes);
305 g_atomic_int_dec_and_test (&ignore_state_changes);
306 release_notifications ();
311 Playlist::delay_notifications ()
313 g_atomic_int_inc (&block_notifications);
314 freeze_length = _get_maximum_extent();
318 Playlist::release_notifications ()
320 if (g_atomic_int_dec_and_test (&block_notifications)) {
321 flush_notifications ();
327 Playlist::notify_modified ()
329 if (holding_state ()) {
330 pending_modified = true;
332 pending_modified = false;
333 Modified(); /* EMIT SIGNAL */
338 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
340 if (holding_state ()) {
341 pending_removes.insert (r);
342 pending_modified = true;
343 pending_length = true;
345 /* this might not be true, but we have to act
346 as though it could be.
348 LengthChanged (); /* EMIT SIGNAL */
349 Modified (); /* EMIT SIGNAL */
354 Playlist::notify_region_added (boost::shared_ptr<Region> r)
356 /* the length change might not be true, but we have to act
357 as though it could be.
360 if (holding_state()) {
361 pending_adds.insert (r);
362 pending_modified = true;
363 pending_length = true;
365 LengthChanged (); /* EMIT SIGNAL */
366 Modified (); /* EMIT SIGNAL */
371 Playlist::notify_length_changed ()
373 if (holding_state ()) {
374 pending_length = true;
376 LengthChanged(); /* EMIT SIGNAL */
377 Modified (); /* EMIT SIGNAL */
382 Playlist::flush_notifications ()
384 set<boost::shared_ptr<Region> > dependent_checks_needed;
385 set<boost::shared_ptr<Region> >::iterator s;
394 /* we have no idea what order the regions ended up in pending
395 bounds (it could be based on selection order, for example).
396 so, to preserve layering in the "most recently moved is higher"
397 model, sort them by existing layer, then timestamp them.
400 // RegionSortByLayer cmp;
401 // pending_bounds.sort (cmp);
403 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
404 if (Config->get_layer_model() == MoveAddHigher) {
405 timestamp_layer_op (*r);
407 pending_length = true;
408 dependent_checks_needed.insert (*r);
412 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
413 dependent_checks_needed.insert (*s);
417 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
418 remove_dependents (*s);
422 if ((freeze_length != _get_maximum_extent()) || pending_length) {
424 LengthChanged(); /* EMIT SIGNAL */
428 if (n || pending_modified) {
432 pending_modified = false;
433 Modified (); /* EMIT SIGNAL */
436 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
437 check_dependents (*s, false);
440 pending_adds.clear ();
441 pending_removes.clear ();
442 pending_bounds.clear ();
447 /*************************************************************
449 *************************************************************/
452 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
454 RegionLock rlock (this);
456 times = fabs (times);
458 int itimes = (int) floor (times);
460 nframes_t pos = position;
463 add_region_internal (region, pos);
464 pos += region->length();
469 /* note that itimes can be zero if we being asked to just
470 insert a single fraction of the region.
473 for (int i = 0; i < itimes; ++i) {
474 boost::shared_ptr<Region> copy = RegionFactory::create (region);
475 add_region_internal (copy, pos);
476 pos += region->length();
479 nframes_t length = 0;
481 if (floor (times) != times) {
482 length = (nframes_t) floor (region->length() * (times - floor (times)));
484 _session.region_name (name, region->name(), false);
485 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
486 add_region_internal (sub, pos);
490 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
494 Playlist::set_region_ownership ()
496 RegionLock rl (this);
497 RegionList::iterator i;
498 boost::weak_ptr<Playlist> pl (shared_from_this());
500 for (i = regions.begin(); i != regions.end(); ++i) {
501 (*i)->set_playlist (pl);
506 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
508 RegionSortByPosition cmp;
509 nframes_t old_length = 0;
511 if (!holding_state()) {
512 old_length = _get_maximum_extent();
515 if (!first_set_state) {
516 boost::shared_ptr<Playlist> foo (shared_from_this());
517 region->set_playlist (boost::weak_ptr<Playlist>(foo));
520 region->set_position (position, this);
522 timestamp_layer_op (region);
524 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
525 all_regions.insert (region);
527 possibly_splice_unlocked (position, region->length(), region);
529 if (!holding_state () && !in_set_state) {
530 /* layers get assigned from XML state */
534 /* we need to notify the existence of new region before checking dependents. Ick. */
536 notify_region_added (region);
538 if (!holding_state ()) {
539 check_dependents (region, false);
540 if (old_length != _get_maximum_extent()) {
541 notify_length_changed ();
545 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
546 boost::weak_ptr<Region> (region)));
550 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
552 RegionLock rlock (this);
554 bool old_sp = _splicing;
557 remove_region_internal (old);
558 add_region_internal (newr, pos);
562 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
566 Playlist::remove_region (boost::shared_ptr<Region> region)
568 RegionLock rlock (this);
569 remove_region_internal (region);
573 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
575 RegionList::iterator i;
576 nframes_t old_length = 0;
578 if (!holding_state()) {
579 old_length = _get_maximum_extent();
584 region->set_playlist (boost::weak_ptr<Playlist>());
587 for (i = regions.begin(); i != regions.end(); ++i) {
590 nframes_t pos = (*i)->position();
591 nframes64_t distance = (*i)->length();
595 possibly_splice_unlocked (pos, -distance);
597 if (!holding_state ()) {
599 remove_dependents (region);
601 if (old_length != _get_maximum_extent()) {
602 notify_length_changed ();
606 notify_region_removed (region);
617 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
619 if (Config->get_use_overlap_equivalency()) {
620 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
621 if ((*i)->overlap_equivalent (other)) {
622 results.push_back ((*i));
626 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
627 if ((*i)->equivalent (other)) {
628 results.push_back ((*i));
635 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
637 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
639 if ((*i) && (*i)->region_list_equivalent (other)) {
640 results.push_back (*i);
646 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
650 partition_internal (start, end, false, thawlist);
652 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
653 (*i)->thaw ("separation");
658 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
660 RegionLock rlock (this);
661 boost::shared_ptr<Region> region;
662 boost::shared_ptr<Region> current;
664 RegionList::iterator tmp;
666 nframes_t pos1, pos2, pos3, pos4;
667 RegionList new_regions;
671 /* need to work from a copy, because otherwise the regions we add during the process
672 get operated on as well.
675 RegionList copy = regions;
677 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
684 if (current->first_frame() == start && current->last_frame() == end) {
686 remove_region_internal (current);
691 if ((overlap = current->coverage (start, end)) == OverlapNone) {
695 pos1 = current->position();
698 pos4 = current->last_frame();
700 if (overlap == OverlapInternal) {
702 /* split: we need 3 new regions, the front, middle and end.
703 cut: we need 2 regions, the front and end.
708 ---------------*************************------------
711 ---------------*****++++++++++++++++====------------
713 ---------------*****----------------====------------
719 /* "middle" ++++++ */
721 _session.region_name (new_name, current->name(), false);
722 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
723 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
724 add_region_internal (region, start);
725 new_regions.push_back (region);
730 _session.region_name (new_name, current->name(), false);
731 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
732 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
734 add_region_internal (region, end);
735 new_regions.push_back (region);
740 thawlist.push_back (current);
741 current->trim_end (pos2, this);
743 } else if (overlap == OverlapEnd) {
747 ---------------*************************------------
750 ---------------**************+++++++++++------------
752 ---------------**************-----------------------
760 _session.region_name (new_name, current->name(), false);
761 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
762 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
763 add_region_internal (region, start);
764 new_regions.push_back (region);
770 thawlist.push_back (current);
771 current->trim_end (pos2, this);
773 } else if (overlap == OverlapStart) {
775 /* split: we need 2 regions: the front and the end.
776 cut: just trim current to skip the cut area
781 ---------------*************************------------
785 ---------------****+++++++++++++++++++++------------
787 -------------------*********************------------
794 _session.region_name (new_name, current->name(), false);
795 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
796 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
797 add_region_internal (region, pos1);
798 new_regions.push_back (region);
804 thawlist.push_back (current);
805 current->trim_front (pos3, this);
807 } else if (overlap == OverlapExternal) {
809 /* split: no split required.
810 cut: remove the region.
815 ---------------*************************------------
819 ---------------*************************------------
821 ----------------------------------------------------
826 remove_region_internal (current);
828 new_regions.push_back (current);
832 in_partition = false;
834 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
835 check_dependents (*i, false);
839 boost::shared_ptr<Playlist>
840 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
842 boost::shared_ptr<Playlist> ret;
843 boost::shared_ptr<Playlist> pl;
846 if (ranges.empty()) {
847 return boost::shared_ptr<Playlist>();
850 start = ranges.front().start;
852 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
854 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
856 if (i == ranges.begin()) {
860 /* paste the next section into the nascent playlist,
861 offset to reflect the start of the first range we
865 ret->paste (pl, (*i).start - start, 1.0f);
872 boost::shared_ptr<Playlist>
873 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
875 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
876 return cut_copy (pmf, ranges, result_is_hidden);
879 boost::shared_ptr<Playlist>
880 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
882 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
883 return cut_copy (pmf, ranges, result_is_hidden);
886 boost::shared_ptr<Playlist>
887 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
889 boost::shared_ptr<Playlist> the_copy;
893 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
894 string new_name = _name;
898 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
899 return boost::shared_ptr<Playlist>();
902 partition_internal (start, start+cnt-1, true, thawlist);
904 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
905 (*i)->thaw ("playlist cut");
911 boost::shared_ptr<Playlist>
912 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
916 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
917 string new_name = _name;
921 cnt = min (_get_maximum_extent() - start, cnt);
922 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
926 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
928 times = fabs (times);
929 nframes_t old_length;
932 RegionLock rl1 (this);
933 RegionLock rl2 (other.get());
935 old_length = _get_maximum_extent();
937 int itimes = (int) floor (times);
938 nframes_t pos = position;
939 nframes_t shift = other->_get_maximum_extent();
940 layer_t top_layer = regions.size();
943 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
944 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
946 /* put these new regions on top of all existing ones, but preserve
947 the ordering they had in the original playlist.
950 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
951 add_region_internal (copy_of_region, copy_of_region->position() + pos);
957 /* XXX shall we handle fractional cases at some point? */
959 if (old_length != _get_maximum_extent()) {
960 notify_length_changed ();
971 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
973 times = fabs (times);
975 RegionLock rl (this);
976 int itimes = (int) floor (times);
977 nframes_t pos = position;
980 boost::shared_ptr<Region> copy = RegionFactory::create (region);
981 add_region_internal (copy, pos);
982 pos += region->length();
985 if (floor (times) != times) {
986 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
988 _session.region_name (name, region->name(), false);
989 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
990 add_region_internal (sub, pos);
995 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
997 RegionLock rl (this);
999 if (!region->covers (playlist_position)) {
1003 if (region->position() == playlist_position ||
1004 region->last_frame() == playlist_position) {
1008 boost::shared_ptr<Region> left;
1009 boost::shared_ptr<Region> right;
1015 /* split doesn't change anything about length, so don't try to splice */
1017 bool old_sp = _splicing;
1020 before = playlist_position - region->position();
1021 after = region->length() - before;
1023 _session.region_name (before_name, region->name(), false);
1024 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1026 _session.region_name (after_name, region->name(), false);
1027 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1029 add_region_internal (left, region->position());
1030 add_region_internal (right, region->position() + before);
1032 uint64_t orig_layer_op = region->last_layer_op();
1033 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1034 if ((*i)->last_layer_op() > orig_layer_op) {
1035 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1039 left->set_last_layer_op ( orig_layer_op );
1040 right->set_last_layer_op ( orig_layer_op + 1);
1044 finalize_split_region (region, left, right);
1046 remove_region_internal (region);
1052 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1054 if (_splicing || in_set_state) {
1055 /* don't respond to splicing moves or state setting */
1059 if (_edit_mode == Splice) {
1060 splice_locked (at, distance, exclude);
1065 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1067 if (_splicing || in_set_state) {
1068 /* don't respond to splicing moves or state setting */
1072 if (_edit_mode == Splice) {
1073 splice_unlocked (at, distance, exclude);
1078 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1081 RegionLock rl (this);
1082 core_splice (at, distance, exclude);
1087 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1089 core_splice (at, distance, exclude);
1093 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1097 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1099 if (exclude && (*i) == exclude) {
1103 if ((*i)->position() >= at) {
1104 nframes64_t new_pos = (*i)->position() + distance;
1107 } else if (new_pos >= max_frames - (*i)->length()) {
1108 new_pos = max_frames - (*i)->length();
1111 (*i)->set_position (new_pos, this);
1117 notify_length_changed ();
1121 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1123 if (in_set_state || _splicing || _nudging) {
1127 if (what_changed & ARDOUR::PositionChanged) {
1129 /* remove it from the list then add it back in
1130 the right place again.
1133 RegionSortByPosition cmp;
1135 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1137 if (i == regions.end()) {
1138 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1139 _name, region->name())
1145 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1148 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1150 nframes64_t delta = 0;
1152 if (what_changed & ARDOUR::PositionChanged) {
1153 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1156 if (what_changed & ARDOUR::LengthChanged) {
1157 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1161 possibly_splice (region->last_position() + region->last_length(), delta, region);
1164 if (holding_state ()) {
1165 pending_bounds.push_back (region);
1167 if (Config->get_layer_model() == MoveAddHigher) {
1168 /* it moved or changed length, so change the timestamp */
1169 timestamp_layer_op (region);
1172 notify_length_changed ();
1174 check_dependents (region, false);
1180 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1182 boost::shared_ptr<Region> region (weak_region.lock());
1189 /* this makes a virtual call to the right kind of playlist ... */
1191 region_changed (what_changed, region);
1195 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1197 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1200 if (in_set_state || in_flush) {
1205 if (what_changed & BoundsChanged) {
1206 region_bounds_changed (what_changed, region);
1207 save = !(_splicing || _nudging);
1210 if ((what_changed & our_interests) &&
1211 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1212 check_dependents (region, false);
1215 if (what_changed & our_interests) {
1224 Playlist::drop_regions ()
1226 RegionLock rl (this);
1228 all_regions.clear ();
1232 Playlist::clear (bool with_signals)
1235 RegionLock rl (this);
1236 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1237 pending_removes.insert (*i);
1249 /***********************************************************************
1251 **********************************************************************/
1253 Playlist::RegionList *
1254 Playlist::regions_at (nframes_t frame)
1257 RegionLock rlock (this);
1258 return find_regions_at (frame);
1261 boost::shared_ptr<Region>
1262 Playlist::top_region_at (nframes_t frame)
1265 RegionLock rlock (this);
1266 RegionList *rlist = find_regions_at (frame);
1267 boost::shared_ptr<Region> region;
1269 if (rlist->size()) {
1270 RegionSortByLayer cmp;
1272 region = rlist->back();
1279 Playlist::RegionList*
1280 Playlist::regions_to_read (nframes_t start, nframes_t end)
1282 /* Caller must hold lock */
1284 RegionList covering;
1285 set<nframes_t> to_check;
1286 set<boost::shared_ptr<Region> > unique;
1289 to_check.insert (start);
1290 to_check.insert (end);
1292 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1294 /* find all/any regions that span start+end */
1296 switch ((*i)->coverage (start, end)) {
1300 case OverlapInternal:
1301 covering.push_back (*i);
1305 to_check.insert ((*i)->position());
1306 covering.push_back (*i);
1310 to_check.insert ((*i)->last_frame());
1311 covering.push_back (*i);
1314 case OverlapExternal:
1315 covering.push_back (*i);
1316 to_check.insert ((*i)->position());
1317 to_check.insert ((*i)->last_frame());
1321 /* don't go too far */
1323 if ((*i)->position() > end) {
1328 RegionList* rlist = new RegionList;
1330 /* find all the regions that cover each position .... */
1332 if (covering.size() == 1) {
1334 rlist->push_back (covering.front());
1338 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1342 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1344 if ((*x)->covers (*t)) {
1345 here.push_back (*x);
1349 RegionSortByLayer cmp;
1352 /* ... and get the top/transparent regions at "here" */
1354 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1358 if ((*c)->opaque()) {
1360 /* the other regions at this position are hidden by this one */
1367 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1368 rlist->push_back (*s);
1371 if (rlist->size() > 1) {
1372 /* now sort by time order */
1374 RegionSortByPosition cmp;
1382 Playlist::RegionList *
1383 Playlist::find_regions_at (nframes_t frame)
1385 /* Caller must hold lock */
1387 RegionList *rlist = new RegionList;
1389 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1390 if ((*i)->covers (frame)) {
1391 rlist->push_back (*i);
1398 Playlist::RegionList *
1399 Playlist::regions_touched (nframes_t start, nframes_t end)
1401 RegionLock rlock (this);
1402 RegionList *rlist = new RegionList;
1404 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1405 if ((*i)->coverage (start, end) != OverlapNone) {
1406 rlist->push_back (*i);
1414 boost::shared_ptr<Region>
1415 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1417 RegionLock rlock (this);
1418 boost::shared_ptr<Region> ret;
1419 nframes_t closest = max_frames;
1422 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1425 boost::shared_ptr<Region> r = (*i);
1430 pos = r->first_frame ();
1433 pos = r->last_frame ();
1436 pos = r->adjust_to_sync (r->first_frame());
1441 case 1: /* forwards */
1444 if ((distance = pos - frame) < closest) {
1452 default: /* backwards */
1455 if ((distance = frame - pos) < closest) {
1468 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1470 RegionLock rlock (this);
1472 nframes64_t closest = max_frames;
1473 nframes64_t ret = -1;
1477 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1479 boost::shared_ptr<Region> r = (*i);
1480 nframes64_t distance;
1485 if (r->first_frame() > frame) {
1487 distance = r->first_frame() - frame;
1489 if (distance < closest) {
1490 ret = r->first_frame();
1496 if (r->last_frame() > frame) {
1498 distance = r->last_frame() - frame;
1500 if (distance < closest) {
1501 ret = r->last_frame();
1514 for (RegionList::const_reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1516 boost::shared_ptr<Region> r = (*i);
1517 nframes64_t distance;
1522 if (r->last_frame() < frame) {
1524 distance = frame - r->last_frame();
1526 if (distance < closest) {
1527 ret = r->last_frame();
1533 if (r->first_frame() < frame) {
1534 distance = frame - r->last_frame();
1536 if (distance < closest) {
1537 ret = r->first_frame();
1552 /***********************************************************************/
1557 Playlist::mark_session_dirty ()
1559 if (!in_set_state && !holding_state ()) {
1560 _session.set_dirty();
1565 Playlist::set_state (const XMLNode& node)
1569 XMLNodeConstIterator niter;
1570 XMLPropertyList plist;
1571 XMLPropertyConstIterator piter;
1573 boost::shared_ptr<Region> region;
1578 if (node.name() != "Playlist") {
1585 plist = node.properties();
1587 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1591 if (prop->name() == X_("name")) {
1592 _name = prop->value();
1593 } else if (prop->name() == X_("orig_diskstream_id")) {
1594 _orig_diskstream_id = prop->value ();
1595 } else if (prop->name() == X_("frozen")) {
1596 _frozen = (prop->value() == X_("yes"));
1602 nlist = node.children();
1604 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1608 if (child->name() == "Region") {
1610 if ((prop = child->property ("id")) == 0) {
1611 error << _("region state node has no ID, ignored") << endmsg;
1615 ID id = prop->value ();
1617 if ((region = region_by_id (id))) {
1619 Change what_changed = Change (0);
1621 if (region->set_live_state (*child, what_changed, true)) {
1622 error << _("Playlist: cannot reset region state from XML") << endmsg;
1626 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1627 error << _("Playlist: cannot create region from XML") << endmsg;
1631 add_region (region, region->position(), 1.0);
1633 // So that layer_op ordering doesn't get screwed up
1634 region->set_last_layer_op( region->layer());
1643 /* update dependents, which was not done during add_region_internal
1644 due to in_set_state being true
1647 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1648 check_dependents (*r, false);
1652 first_set_state = false;
1657 Playlist::get_state()
1663 Playlist::get_template()
1665 return state(false);
1669 Playlist::state (bool full_state)
1671 XMLNode *node = new XMLNode (X_("Playlist"));
1674 node->add_property (X_("name"), _name);
1676 _orig_diskstream_id.print (buf, sizeof (buf));
1677 node->add_property (X_("orig_diskstream_id"), buf);
1678 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1681 RegionLock rlock (this, false);
1682 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1683 node->add_child_nocopy ((*i)->get_state());
1688 node->add_child_copy (*_extra_xml);
1695 Playlist::empty() const
1697 RegionLock rlock (const_cast<Playlist *>(this), false);
1698 return regions.empty();
1702 Playlist::n_regions() const
1704 RegionLock rlock (const_cast<Playlist *>(this), false);
1705 return regions.size();
1709 Playlist::get_maximum_extent () const
1711 RegionLock rlock (const_cast<Playlist *>(this), false);
1712 return _get_maximum_extent ();
1716 Playlist::_get_maximum_extent () const
1718 RegionList::const_iterator i;
1719 nframes_t max_extent = 0;
1722 for (i = regions.begin(); i != regions.end(); ++i) {
1723 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1732 Playlist::bump_name (string name, Session &session)
1734 string newname = name;
1737 newname = Playlist::bump_name_once (newname);
1738 } while (session.playlist_by_name (newname)!=NULL);
1744 Playlist::bump_name_once (string name)
1746 string::size_type period;
1749 if ((period = name.find_last_of ('.')) == string::npos) {
1754 const char *last_element = name.c_str() + period + 1;
1755 for (size_t i = 0; i < strlen(last_element); i++) {
1756 if (!isdigit(last_element[i])) {
1763 long int version = strtol (name.c_str()+period+1, (char **)NULL, 10);
1765 if (isnumber == 0 || errno != 0) {
1766 // last_element is not a number, or is too large
1772 snprintf (buf, sizeof(buf), "%ld", version+1);
1774 newname = name.substr (0, period+1);
1783 Playlist::top_layer() const
1785 RegionLock rlock (const_cast<Playlist *> (this));
1788 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1789 top = max (top, (*i)->layer());
1795 Playlist::set_edit_mode (EditMode mode)
1800 /********************
1802 ********************/
1805 Playlist::relayer ()
1807 RegionList::iterator i;
1810 /* don't send multiple Modified notifications
1811 when multiple regions are relayered.
1816 if (Config->get_layer_model() == MoveAddHigher ||
1817 Config->get_layer_model() == AddHigher) {
1819 RegionSortByLastLayerOp cmp;
1820 RegionList copy = regions;
1824 for (i = copy.begin(); i != copy.end(); ++i) {
1825 (*i)->set_layer (layer++);
1830 /* Session::LaterHigher model */
1832 for (i = regions.begin(); i != regions.end(); ++i) {
1833 (*i)->set_layer (layer++);
1837 /* sending Modified means that various kinds of layering
1838 models operate correctly at the GUI
1839 level. slightly inefficient, but only slightly.
1841 We force a Modified signal here in case no layers actually
1850 /* XXX these layer functions are all deprecated */
1853 Playlist::raise_region (boost::shared_ptr<Region> region)
1855 uint32_t rsz = regions.size();
1856 layer_t target = region->layer() + 1U;
1858 if (target >= rsz) {
1859 /* its already at the effective top */
1863 move_region_to_layer (target, region, 1);
1867 Playlist::lower_region (boost::shared_ptr<Region> region)
1869 if (region->layer() == 0) {
1870 /* its already at the bottom */
1874 layer_t target = region->layer() - 1U;
1876 move_region_to_layer (target, region, -1);
1880 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
1882 /* does nothing useful if layering mode is later=higher */
1883 if ((Config->get_layer_model() == MoveAddHigher) ||
1884 (Config->get_layer_model() == AddHigher)) {
1885 timestamp_layer_op (region);
1891 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
1893 /* does nothing useful if layering mode is later=higher */
1894 if ((Config->get_layer_model() == MoveAddHigher) ||
1895 (Config->get_layer_model() == AddHigher)) {
1896 region->set_last_layer_op (0);
1902 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
1904 RegionList::iterator i;
1905 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
1906 list<LayerInfo> layerinfo;
1910 RegionLock rlock (const_cast<Playlist *> (this));
1912 for (i = regions.begin(); i != regions.end(); ++i) {
1920 /* region is moving up, move all regions on intermediate layers
1924 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
1925 dest = (*i)->layer() - 1;
1932 /* region is moving down, move all regions on intermediate layers
1936 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
1937 dest = (*i)->layer() + 1;
1947 newpair.second = dest;
1949 layerinfo.push_back (newpair);
1953 /* now reset the layers without holding the region lock */
1955 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1956 x->first->set_layer (x->second);
1959 region->set_layer (target_layer);
1962 /* now check all dependents */
1964 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1965 check_dependents (x->first, false);
1968 check_dependents (region, false);
1975 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
1977 RegionList::iterator i;
1984 RegionLock rlock (const_cast<Playlist *> (this));
1986 for (i = regions.begin(); i != regions.end(); ++i) {
1988 if ((*i)->position() >= start) {
1992 if ((*i)->last_frame() > max_frames - distance) {
1993 new_pos = max_frames - (*i)->length();
1995 new_pos = (*i)->position() + distance;
2000 if ((*i)->position() > distance) {
2001 new_pos = (*i)->position() - distance;
2007 (*i)->set_position (new_pos, this);
2015 notify_length_changed ();
2020 boost::shared_ptr<Region>
2021 Playlist::find_region (const ID& id) const
2023 RegionLock rlock (const_cast<Playlist*> (this));
2025 /* searches all regions currently in use by the playlist */
2027 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2028 if ((*i)->id() == id) {
2033 return boost::shared_ptr<Region> ();
2036 boost::shared_ptr<Region>
2037 Playlist::region_by_id (ID id)
2039 /* searches all regions ever added to this playlist */
2041 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2042 if ((*i)->id() == id) {
2046 return boost::shared_ptr<Region> ();
2050 Playlist::dump () const
2052 boost::shared_ptr<Region> r;
2054 cerr << "Playlist \"" << _name << "\" " << endl
2055 << regions.size() << " regions "
2058 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2060 cerr << " " << r->name() << " ["
2061 << r->start() << "+" << r->length()
2071 Playlist::set_frozen (bool yn)
2077 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2079 // struct timeval tv;
2080 // gettimeofday (&tv, 0);
2081 region->set_last_layer_op (++layer_op_counter);