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.
29 #include <sigc++/bind.h>
31 #include <pbd/failed_constructor.h>
32 #include <pbd/stl_delete.h>
33 #include <pbd/xml++.h>
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
43 using namespace ARDOUR;
46 sigc::signal<void,Playlist*> Playlist::PlaylistCreated;
48 struct ShowMeTheList {
49 ShowMeTheList (Playlist *pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
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, DataType type, bool hide)
84 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
88 const XMLProperty* prop = node.property("type");
89 assert(!prop || DataType(prop->value()) == _type);
92 _name = "unnamed"; /* reset by set_state */
94 if (set_state (node)) {
95 throw failed_constructor();
99 Playlist::Playlist (const Playlist& other, string namestr, bool hide)
100 : _name (namestr), _session (other._session), _type(other._type), _orig_diskstream_id(other._orig_diskstream_id)
105 other.copy_regions (tmp);
109 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
110 add_region_internal( (*x), (*x)->position() );
113 in_set_state = false;
115 _splicing = other._splicing;
116 _nudging = other._nudging;
117 _edit_mode = other._edit_mode;
119 in_set_state = false;
121 in_partition = false;
123 _read_data_count = 0;
124 _frozen = other._frozen;
125 save_on_thaw = false;
127 layer_op_counter = other.layer_op_counter;
128 freeze_length = other.freeze_length;
132 Playlist::Playlist (const Playlist& other, nframes_t start, nframes_t cnt, string str, bool hide)
133 : _name (str), _session (other._session), _type(other._type), _orig_diskstream_id(other._orig_diskstream_id)
135 RegionLock rlock2 (&((Playlist&)other));
137 nframes_t end = start + cnt - 1;
141 for (RegionList::const_iterator i = other.regions.begin(); i != other.regions.end(); i++) {
143 boost::shared_ptr<Region> region;
144 boost::shared_ptr<Region> new_region;
145 nframes_t offset = 0;
146 nframes_t position = 0;
153 overlap = region->coverage (start, end);
159 case OverlapInternal:
160 offset = start - region->position();
167 position = region->position() - start;
168 len = end - region->position();
172 offset = start - region->position();
174 len = region->length() - offset;
177 case OverlapExternal:
179 position = region->position() - start;
180 len = region->length();
184 _session.region_name (new_name, region->name(), false);
186 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
188 add_region_internal (new_region, position, true);
191 /* this constructor does NOT notify others (session) */
198 InUse (this, true); /* EMIT SIGNAL */
208 InUse (this, false); /* EMIT SIGNAL */
211 /* nobody knows we exist */
219 Playlist::copy_regions (RegionList& newlist) const
221 RegionLock rlock (const_cast<Playlist *> (this));
223 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
224 newlist.push_back (RegionFactory::RegionFactory::create (*i));
229 Playlist::init (bool hide)
231 g_atomic_int_set (&block_notifications, 0);
232 g_atomic_int_set (&ignore_state_changes, 0);
233 pending_modified = false;
234 pending_length = false;
239 in_set_state = false;
240 _edit_mode = Config->get_edit_mode();
242 in_partition = false;
244 _read_data_count = 0;
246 save_on_thaw = false;
247 layer_op_counter = 0;
250 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
253 Playlist::Playlist (const Playlist& pl)
254 : _session (pl._session)
255 , _type(pl.data_type())
257 fatal << _("playlist const copy constructor called") << endmsg;
260 Playlist::Playlist (Playlist& pl)
261 : _session (pl._session)
262 , _type(pl.data_type())
264 fatal << _("playlist non-const copy constructor called") << endmsg;
267 Playlist::~Playlist ()
269 /* GoingAway must be emitted by derived classes */
273 Playlist::set_name (const 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.
286 NameChanged(); /* EMIT SIGNAL */
289 /***********************************************************************
290 CHANGE NOTIFICATION HANDLING
292 Notifications must be delayed till the region_lock is released. This
293 is necessary because handlers for the signals may need to acquire
294 the lock (e.g. to read from the playlist).
295 ***********************************************************************/
300 delay_notifications ();
301 g_atomic_int_inc (&ignore_state_changes);
307 g_atomic_int_dec_and_test (&ignore_state_changes);
308 release_notifications ();
313 Playlist::delay_notifications ()
315 g_atomic_int_inc (&block_notifications);
316 freeze_length = _get_maximum_extent();
320 Playlist::release_notifications ()
322 if (g_atomic_int_dec_and_test (&block_notifications)) {
323 flush_notifications ();
329 Playlist::notify_modified ()
331 if (holding_state ()) {
332 pending_modified = true;
334 pending_modified = false;
335 Modified(); /* EMIT SIGNAL */
340 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
342 if (holding_state ()) {
343 pending_removals.insert (pending_removals.end(), r);
345 RegionRemoved (r); /* EMIT SIGNAL */
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 if (holding_state()) {
358 pending_adds.insert (pending_adds.end(), r);
360 RegionAdded (r); /* EMIT SIGNAL */
361 /* this might not be true, but we have to act
362 as though it could be.
364 LengthChanged (); /* EMIT SIGNAL */
365 Modified (); /* EMIT SIGNAL */
370 Playlist::notify_length_changed ()
372 if (holding_state ()) {
373 pending_length = true;
375 LengthChanged(); /* EMIT SIGNAL */
376 Modified (); /* EMIT SIGNAL */
381 Playlist::flush_notifications ()
383 RegionList::iterator r;
384 RegionList::iterator a;
385 set<boost::shared_ptr<Region> > dependent_checks_needed;
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;
411 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
412 dependent_checks_needed.insert (*r);
413 /* don't increment n again - its the same list */
416 for (a = pending_adds.begin(); a != pending_adds.end(); ++a) {
417 dependent_checks_needed.insert (*a);
418 RegionAdded (*a); /* EMIT SIGNAL */
422 for (set<boost::shared_ptr<Region> >::iterator x = dependent_checks_needed.begin(); x != dependent_checks_needed.end(); ++x) {
423 check_dependents (*x, false);
426 for (r = pending_removals.begin(); r != pending_removals.end(); ++r) {
427 remove_dependents (*r);
428 RegionRemoved (*r); /* EMIT SIGNAL */
432 if ((freeze_length != _get_maximum_extent()) || pending_length) {
434 LengthChanged(); /* EMIT SIGNAL */
438 if (n || pending_modified) {
443 pending_modified = false;
444 Modified (); /* EMIT SIGNAL */
447 pending_adds.clear ();
448 pending_removals.clear ();
449 pending_bounds.clear ();
452 save_on_thaw = false;
453 save_state (last_save_reason);
459 /*************************************************************
461 *************************************************************/
464 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool with_save)
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, true);
476 pos += region->length();
480 /* later regions will all be spliced anyway */
482 if (!holding_state ()) {
483 possibly_splice_unlocked ();
486 /* note that itimes can be zero if we being asked to just
487 insert a single fraction of the region.
490 for (int i = 0; i < itimes; ++i) {
491 boost::shared_ptr<Region> copy = RegionFactory::create (region);
492 add_region_internal (copy, pos, true);
493 pos += region->length();
496 if (floor (times) != times) {
497 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
499 _session.region_name (name, region->name(), false);
500 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
501 add_region_internal (sub, pos, true);
505 maybe_save_state (_("add region"));
510 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position, bool delay_sort)
512 RegionSortByPosition cmp;
513 nframes_t old_length = 0;
515 if (!holding_state()) {
516 old_length = _get_maximum_extent();
519 region->set_playlist (this);
520 region->set_position (position, this);
522 timestamp_layer_op (region);
524 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
526 if (!holding_state () && !in_set_state) {
527 /* layers get assigned from XML state */
531 /* we need to notify the existence of new region before checking dependents. Ick. */
533 notify_region_added (region);
535 if (!holding_state ()) {
536 check_dependents (region, false);
537 if (old_length != _get_maximum_extent()) {
538 notify_length_changed ();
542 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
543 boost::weak_ptr<Region> (region)));
547 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
549 RegionLock rlock (this);
551 remove_region_internal (old);
552 add_region_internal (newr, pos);
554 if (!holding_state ()) {
555 possibly_splice_unlocked ();
558 maybe_save_state (_("replace region"));
562 Playlist::remove_region (boost::shared_ptr<Region> region)
564 RegionLock rlock (this);
565 remove_region_internal (region);
567 if (!holding_state ()) {
568 possibly_splice_unlocked ();
571 maybe_save_state (_("remove region"));
575 Playlist::remove_region_internal (boost::shared_ptr<Region>region, bool delay_sort)
577 RegionList::iterator i;
578 nframes_t old_length = 0;
580 // cerr << "removing region " << region->name() << endl;
582 if (!holding_state()) {
583 old_length = _get_maximum_extent();
586 for (i = regions.begin(); i != regions.end(); ++i) {
591 if (!holding_state ()) {
593 remove_dependents (region);
595 if (old_length != _get_maximum_extent()) {
596 notify_length_changed ();
600 notify_region_removed (region);
608 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
610 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
611 if (Config->get_use_overlap_equivalency()) {
612 if ((*i)->overlap_equivalent (other)) {
613 results.push_back ((*i));
614 } else if ((*i)->equivalent (other)) {
615 results.push_back ((*i));
622 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
624 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
626 if ((*i) && (*i)->region_list_equivalent (other)) {
627 results.push_back (*i);
633 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
637 partition_internal (start, end, false, thawlist);
639 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
640 (*i)->thaw ("separation");
643 maybe_save_state (_("separate"));
647 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
649 RegionLock rlock (this);
650 boost::shared_ptr<Region> region;
651 boost::shared_ptr<Region> current;
653 RegionList::iterator tmp;
655 nframes_t pos1, pos2, pos3, pos4;
656 RegionList new_regions;
660 /* need to work from a copy, because otherwise the regions we add during the process
661 get operated on as well.
664 RegionList copy = regions;
666 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
673 if (current->first_frame() == start && current->last_frame() == end) {
675 remove_region_internal (current);
680 if ((overlap = current->coverage (start, end)) == OverlapNone) {
684 pos1 = current->position();
687 pos4 = current->last_frame();
689 if (overlap == OverlapInternal) {
691 /* split: we need 3 new regions, the front, middle and end.
692 cut: we need 2 regions, the front and end.
697 ---------------*************************------------
700 ---------------*****++++++++++++++++====------------
702 ---------------*****----------------====------------
708 /* "middle" ++++++ */
710 _session.region_name (new_name, current->name(), false);
711 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
712 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
713 add_region_internal (region, start, true);
714 new_regions.push_back (region);
719 _session.region_name (new_name, current->name(), false);
720 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
721 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
723 add_region_internal (region, end, true);
724 new_regions.push_back (region);
729 thawlist.push_back (current);
730 current->trim_end (pos2, this);
732 } else if (overlap == OverlapEnd) {
736 ---------------*************************------------
739 ---------------**************+++++++++++------------
741 ---------------**************-----------------------
749 _session.region_name (new_name, current->name(), false);
750 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
751 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
752 add_region_internal (region, start, true);
753 new_regions.push_back (region);
759 thawlist.push_back (current);
760 current->trim_end (pos2, this);
762 } else if (overlap == OverlapStart) {
764 /* split: we need 2 regions: the front and the end.
765 cut: just trim current to skip the cut area
770 ---------------*************************------------
774 ---------------****+++++++++++++++++++++------------
776 -------------------*********************------------
783 _session.region_name (new_name, current->name(), false);
784 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
785 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
786 add_region_internal (region, pos1, true);
787 new_regions.push_back (region);
793 thawlist.push_back (current);
794 current->trim_front (pos3, this);
796 } else if (overlap == OverlapExternal) {
798 /* split: no split required.
799 cut: remove the region.
804 ---------------*************************------------
808 ---------------*************************------------
810 ----------------------------------------------------
815 remove_region_internal (current);
817 new_regions.push_back (current);
821 in_partition = false;
823 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
824 check_dependents (*i, false);
829 Playlist::cut_copy (Playlist* (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
835 if (ranges.empty()) {
839 start = ranges.front().start;
842 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
844 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
846 if (i == ranges.begin()) {
850 /* paste the next section into the nascent playlist,
851 offset to reflect the start of the first range we
855 ret->paste (*pl, (*i).start - start, 1.0f);
861 /* manually notify session of new playlist here
862 because the playlists were constructed without notifying
864 PlaylistCreated (ret);
871 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
873 Playlist* (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
874 return cut_copy (pmf, ranges, result_is_hidden);
878 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
880 Playlist* (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
881 return cut_copy (pmf, ranges, result_is_hidden);
885 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
891 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
892 string new_name = _name;
896 if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
900 partition_internal (start, start+cnt-1, true, thawlist);
903 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
904 (*i)->thaw ("playlist cut");
907 maybe_save_state (_("cut"));
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 copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
927 Playlist::paste (Playlist& other, nframes_t position, float times)
929 times = fabs (times);
930 nframes_t old_length;
933 RegionLock rl1 (this);
934 RegionLock rl2 (&other);
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);
957 possibly_splice_unlocked ();
959 /* XXX shall we handle fractional cases at some point? */
961 if (old_length != _get_maximum_extent()) {
962 notify_length_changed ();
968 maybe_save_state (_("paste"));
975 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
977 times = fabs (times);
979 RegionLock rl (this);
980 int itimes = (int) floor (times);
981 nframes_t pos = position;
984 boost::shared_ptr<Region> copy = RegionFactory::create (region);
985 add_region_internal (copy, pos, true);
986 pos += region->length();
989 if (floor (times) != times) {
990 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
992 _session.region_name (name, region->name(), false);
993 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
994 add_region_internal (sub, pos, true);
997 maybe_save_state (_("duplicate"));
1001 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1003 RegionLock rl (this);
1005 if (!region->covers (playlist_position)) {
1009 if (region->position() == playlist_position ||
1010 region->last_frame() == playlist_position) {
1014 boost::shared_ptr<Region> left;
1015 boost::shared_ptr<Region> right;
1021 before = playlist_position - region->position();
1022 after = region->length() - before;
1025 _session.region_name (before_name, region->name(), false);
1026 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1028 _session.region_name (after_name, region->name(), false);
1029 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1031 add_region_internal (left, region->position(), true);
1032 add_region_internal (right, region->position() + before);
1034 uint64_t orig_layer_op = region->last_layer_op();
1035 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1036 if ((*i)->last_layer_op() > orig_layer_op) {
1037 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1041 left->set_last_layer_op ( orig_layer_op );
1042 right->set_last_layer_op ( orig_layer_op + 1);
1046 finalize_split_region (region, left, right);
1048 if (remove_region_internal (region, true)) {
1052 maybe_save_state (_("split"));
1056 Playlist::possibly_splice ()
1058 if (_edit_mode == Splice) {
1064 Playlist::possibly_splice_unlocked ()
1066 if (_edit_mode == Splice) {
1072 Playlist::splice_locked ()
1075 RegionLock rl (this);
1079 notify_length_changed ();
1083 Playlist::splice_unlocked ()
1086 notify_length_changed ();
1090 Playlist::core_splice ()
1094 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1096 RegionList::iterator next;
1101 if (next == regions.end()) {
1105 (*next)->set_position ((*i)->last_frame() + 1, this);
1112 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1114 if (in_set_state || _splicing || _nudging) {
1118 if (what_changed & ARDOUR::PositionChanged) {
1120 /* remove it from the list then add it back in
1121 the right place again.
1124 RegionSortByPosition cmp;
1126 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1128 if (i == regions.end()) {
1129 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1130 _name, region->name())
1136 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1140 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1142 if (holding_state ()) {
1143 pending_bounds.push_back (region);
1145 if (Config->get_layer_model() == MoveAddHigher) {
1146 /* it moved or changed length, so change the timestamp */
1147 timestamp_layer_op (region);
1151 check_dependents (region, false);
1152 notify_length_changed ();
1159 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1161 boost::shared_ptr<Region> region (weak_region.lock());
1167 /* this makes a virtual call to the right kind of playlist ... */
1169 region_changed (what_changed, region);
1173 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1175 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1178 if (in_set_state || in_flush) {
1183 if (what_changed & BoundsChanged) {
1184 region_bounds_changed (what_changed, region);
1185 save = !(_splicing || _nudging);
1188 if ((what_changed & Region::MuteChanged) &&
1189 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1190 check_dependents (region, false);
1193 if (what_changed & our_interests) {
1202 Playlist::clear (bool with_save)
1204 RegionList::iterator i;
1208 RegionLock rl (this);
1213 for (i = tmp.begin(); i != tmp.end(); ++i) {
1214 notify_region_removed (*i);
1218 maybe_save_state (_("clear"));
1222 /***********************************************************************
1224 **********************************************************************/
1226 Playlist::RegionList *
1227 Playlist::regions_at (nframes_t frame)
1230 RegionLock rlock (this);
1231 return find_regions_at (frame);
1234 boost::shared_ptr<Region>
1235 Playlist::top_region_at (nframes_t frame)
1238 RegionLock rlock (this);
1239 RegionList *rlist = find_regions_at (frame);
1240 boost::shared_ptr<Region> region;
1242 if (rlist->size()) {
1243 RegionSortByLayer cmp;
1245 region = rlist->back();
1252 Playlist::RegionList *
1253 Playlist::find_regions_at (nframes_t frame)
1255 RegionList *rlist = new RegionList;
1257 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1258 if ((*i)->covers (frame)) {
1259 rlist->push_back (*i);
1266 Playlist::RegionList *
1267 Playlist::regions_touched (nframes_t start, nframes_t end)
1269 RegionLock rlock (this);
1270 RegionList *rlist = new RegionList;
1272 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1273 if ((*i)->coverage (start, end) != OverlapNone) {
1274 rlist->push_back (*i);
1282 boost::shared_ptr<Region>
1283 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1285 RegionLock rlock (this);
1286 boost::shared_ptr<Region> ret;
1287 nframes_t closest = max_frames;
1289 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1292 boost::shared_ptr<Region> r = (*i);
1297 pos = r->first_frame ();
1300 pos = r->last_frame ();
1303 pos = r->adjust_to_sync (r->first_frame());
1308 case 1: /* forwards */
1311 if ((distance = pos - frame) < closest) {
1319 default: /* backwards */
1322 if ((distance = frame - pos) < closest) {
1334 /***********************************************************************/
1339 Playlist::mark_session_dirty ()
1341 if (!in_set_state && !holding_state ()) {
1342 _session.set_dirty();
1347 Playlist::set_state (const XMLNode& node)
1349 in_set_state = true;
1353 XMLNodeConstIterator niter;
1354 XMLPropertyList plist;
1355 XMLPropertyConstIterator piter;
1357 boost::shared_ptr<Region> region;
1362 if (node.name() != "Playlist") {
1363 in_set_state = false;
1367 plist = node.properties();
1369 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1373 if (prop->name() == X_("name")) {
1374 _name = prop->value();
1375 } else if (prop->name() == X_("orig_diskstream_id")) {
1376 _orig_diskstream_id = prop->value ();
1377 } else if (prop->name() == X_("frozen")) {
1378 _frozen = (prop->value() == X_("yes"));
1382 nlist = node.children();
1384 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1388 if (child->name() == "Region") {
1390 if ((prop = child->property ("id")) == 0) {
1391 error << _("region state node has no ID, ignored") << endmsg;
1395 if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1396 error << _("Playlist: cannot create region from state file") << endmsg;
1400 add_region (region, region->position(), 1.0, false);
1402 // So that layer_op ordering doesn't get screwed up
1403 region->set_last_layer_op( region->layer());
1409 /* update dependents, which was not done during add_region_internal
1410 due to in_set_state being true
1413 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1414 check_dependents (*r, false);
1417 in_set_state = false;
1423 Playlist::get_state()
1429 Playlist::get_template()
1431 return state(false);
1435 Playlist::state (bool full_state)
1437 XMLNode *node = new XMLNode (X_("Playlist"));
1440 node->add_property (X_("name"), _name);
1441 node->add_property (X_("type"), _type.to_string());
1443 _orig_diskstream_id.print (buf, sizeof (buf));
1444 node->add_property (X_("orig_diskstream_id"), buf);
1445 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1448 RegionLock rlock (this, false);
1450 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1451 node->add_child_nocopy ((*i)->get_state());
1456 node->add_child_copy (*_extra_xml);
1463 Playlist::empty() const
1465 return regions.empty();
1469 Playlist::get_maximum_extent () const
1471 RegionLock rlock (const_cast<Playlist *>(this));
1472 return _get_maximum_extent ();
1476 Playlist::_get_maximum_extent () const
1478 RegionList::const_iterator i;
1479 nframes_t max_extent = 0;
1482 for (i = regions.begin(); i != regions.end(); ++i) {
1483 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1492 Playlist::bump_name (string name, Session &session)
1494 string newname = name;
1497 newname = Playlist::bump_name_once (newname);
1498 } while (session.playlist_by_name(newname)!=NULL);
1504 Playlist::bump_name_once (string name)
1506 string::size_type period;
1509 if ((period = name.find_last_of ('.')) == string::npos) {
1516 sscanf (name.substr (period+1).c_str(), "%d", &version);
1517 snprintf (buf, sizeof(buf), "%d", version+1);
1519 newname = name.substr (0, period+1);
1527 Playlist::top_layer() const
1529 RegionLock rlock (const_cast<Playlist *> (this));
1532 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1533 top = max (top, (*i)->layer());
1539 Playlist::set_edit_mode (EditMode mode)
1544 /********************
1546 ********************/
1549 Playlist::relayer ()
1551 RegionList::iterator i;
1554 /* don't send multiple Modified notifications
1555 when multiple regions are relayered.
1560 if (Config->get_layer_model() == MoveAddHigher ||
1561 Config->get_layer_model() == AddHigher) {
1563 RegionSortByLastLayerOp cmp;
1564 RegionList copy = regions;
1568 for (i = copy.begin(); i != copy.end(); ++i) {
1569 (*i)->set_layer (layer++);
1574 /* Session::LaterHigher model */
1576 for (i = regions.begin(); i != regions.end(); ++i) {
1577 (*i)->set_layer (layer++);
1581 /* sending Modified means that various kinds of layering
1582 models operate correctly at the GUI
1583 level. slightly inefficient, but only slightly.
1585 We force a Modified signal here in case no layers actually
1594 /* XXX these layer functions are all deprecated */
1597 Playlist::raise_region (boost::shared_ptr<Region> region)
1599 uint32_t rsz = regions.size();
1600 layer_t target = region->layer() + 1U;
1602 if (target >= rsz) {
1603 /* its already at the effective top */
1607 move_region_to_layer (target, region, 1);
1611 Playlist::lower_region (boost::shared_ptr<Region> region)
1613 if (region->layer() == 0) {
1614 /* its already at the bottom */
1618 layer_t target = region->layer() - 1U;
1620 move_region_to_layer (target, region, -1);
1624 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
1626 /* does nothing useful if layering mode is later=higher */
1627 if ((Config->get_layer_model() == MoveAddHigher) ||
1628 (Config->get_layer_model() == AddHigher)) {
1629 timestamp_layer_op (region);
1635 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
1637 /* does nothing useful if layering mode is later=higher */
1638 if ((Config->get_layer_model() == MoveAddHigher) ||
1639 (Config->get_layer_model() == AddHigher)) {
1640 region->set_last_layer_op (0);
1646 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
1648 RegionList::iterator i;
1649 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
1650 list<LayerInfo> layerinfo;
1654 RegionLock rlock (const_cast<Playlist *> (this));
1656 for (i = regions.begin(); i != regions.end(); ++i) {
1664 /* region is moving up, move all regions on intermediate layers
1668 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
1669 dest = (*i)->layer() - 1;
1676 /* region is moving down, move all regions on intermediate layers
1680 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
1681 dest = (*i)->layer() + 1;
1691 newpair.second = dest;
1693 layerinfo.push_back (newpair);
1697 /* now reset the layers without holding the region lock */
1699 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1700 x->first->set_layer (x->second);
1703 region->set_layer (target_layer);
1705 /* now check all dependents */
1707 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1708 check_dependents (x->first, false);
1711 check_dependents (region, false);
1717 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
1719 RegionList::iterator i;
1726 RegionLock rlock (const_cast<Playlist *> (this));
1728 for (i = regions.begin(); i != regions.end(); ++i) {
1730 if ((*i)->position() >= start) {
1734 if ((*i)->last_frame() > max_frames - distance) {
1735 new_pos = max_frames - (*i)->length();
1737 new_pos = (*i)->position() + distance;
1742 if ((*i)->position() > distance) {
1743 new_pos = (*i)->position() - distance;
1749 (*i)->set_position (new_pos, this);
1757 maybe_save_state (_("nudged"));
1758 notify_length_changed ();
1763 boost::shared_ptr<Region>
1764 Playlist::find_region (const ID& id) const
1766 RegionLock rlock (const_cast<Playlist*> (this));
1767 RegionList::const_iterator i;
1768 boost::shared_ptr<Region> ret;
1770 for (i = regions.begin(); i != regions.end(); ++i) {
1771 if ((*i)->id() == id) {
1780 Playlist::save_state (std::string why)
1782 if (!in_set_state) {
1783 StateManager::save_state (why);
1788 Playlist::dump () const
1790 boost::shared_ptr<Region> r;
1792 cerr << "Playlist \"" << _name << "\" " << endl
1793 << regions.size() << " regions "
1796 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1798 cerr << " " << r->name() << " ["
1799 << r->start() << "+" << r->length()
1809 Playlist::set_frozen (bool yn)
1815 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
1817 // struct timeval tv;
1818 // gettimeofday (&tv, 0);
1819 region->set_last_layer_op (++layer_op_counter);
1823 Playlist::maybe_save_state (string why)
1825 if (holding_state ()) {
1826 save_on_thaw = true;
1827 last_save_reason = why;