2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sigc++/bind.h>
30 #include <pbd/failed_constructor.h>
31 #include <pbd/stl_delete.h>
32 #include <pbd/xml++.h>
33 #include <pbd/stacktrace.h>
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
39 #include <ardour/playlist_factory.h>
40 #include <ardour/transient_detector.h>
45 using namespace ARDOUR;
48 struct ShowMeTheList {
49 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
53 boost::shared_ptr<Playlist> playlist;
57 struct RegionSortByLayer {
58 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
59 return a->layer() < b->layer();
63 struct RegionSortByPosition {
64 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
65 return a->position() < b->position();
69 struct RegionSortByLastLayerOp {
70 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
71 return a->last_layer_op() < b->last_layer_op();
75 Playlist::Playlist (Session& sess, string nom, bool hide)
79 first_set_state = false;
84 Playlist::Playlist (Session& sess, const XMLNode& node, bool hide)
88 _name = "unnamed"; /* reset by set_state */
90 /* set state called by derived class */
93 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
94 : _name (namestr), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
99 other->copy_regions (tmp);
103 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
104 add_region_internal( (*x), (*x)->position());
109 _splicing = other->_splicing;
110 _nudging = other->_nudging;
111 _edit_mode = other->_edit_mode;
114 first_set_state = false;
116 in_partition = false;
118 _read_data_count = 0;
119 _frozen = other->_frozen;
121 layer_op_counter = other->layer_op_counter;
122 freeze_length = other->freeze_length;
125 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
126 : _name (str), _session (other->_session), _orig_diskstream_id(other->_orig_diskstream_id)
128 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
130 nframes_t end = start + cnt - 1;
136 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
138 boost::shared_ptr<Region> region;
139 boost::shared_ptr<Region> new_region;
140 nframes_t offset = 0;
141 nframes_t position = 0;
148 overlap = region->coverage (start, end);
154 case OverlapInternal:
155 offset = start - region->position();
162 position = region->position() - start;
163 len = end - region->position();
167 offset = start - region->position();
169 len = region->length() - offset;
172 case OverlapExternal:
174 position = region->position() - start;
175 len = region->length();
179 _session.region_name (new_name, region->name(), false);
181 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
183 add_region_internal (new_region, position);
187 first_set_state = false;
189 /* this constructor does NOT notify others (session) */
196 InUse (true); /* EMIT SIGNAL */
207 InUse (false); /* EMIT SIGNAL */
212 Playlist::copy_regions (RegionList& newlist) const
214 RegionLock rlock (const_cast<Playlist *> (this));
216 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
217 newlist.push_back (RegionFactory::RegionFactory::create (*i));
222 Playlist::init (bool hide)
224 g_atomic_int_set (&block_notifications, 0);
225 g_atomic_int_set (&ignore_state_changes, 0);
226 pending_modified = false;
227 pending_length = false;
228 first_set_state = true;
235 _edit_mode = Config->get_edit_mode();
237 in_partition = false;
239 _read_data_count = 0;
241 layer_op_counter = 0;
244 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
247 Playlist::Playlist (const Playlist& pl)
248 : _session (pl._session)
250 fatal << _("playlist const copy constructor called") << endmsg;
253 Playlist::Playlist (Playlist& pl)
254 : _session (pl._session)
256 fatal << _("playlist non-const copy constructor called") << endmsg;
259 Playlist::~Playlist ()
262 RegionLock rl (this);
264 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
265 (*i)->set_playlist (boost::shared_ptr<Playlist>());
269 /* GoingAway must be emitted by derived classes */
273 Playlist::set_name (string str)
275 /* in a typical situation, a playlist is being used
276 by one diskstream and also is referenced by the
277 Session. if there are more references than that,
278 then don't change the name.
291 while (_session.playlist_by_name(name) != 0) {
292 name = bump_name_once(name);
296 NameChanged(); /* EMIT SIGNAL */
299 /***********************************************************************
300 CHANGE NOTIFICATION HANDLING
302 Notifications must be delayed till the region_lock is released. This
303 is necessary because handlers for the signals may need to acquire
304 the lock (e.g. to read from the playlist).
305 ***********************************************************************/
310 delay_notifications ();
311 g_atomic_int_inc (&ignore_state_changes);
317 g_atomic_int_dec_and_test (&ignore_state_changes);
318 release_notifications ();
323 Playlist::delay_notifications ()
325 g_atomic_int_inc (&block_notifications);
326 freeze_length = _get_maximum_extent();
330 Playlist::release_notifications ()
332 if (g_atomic_int_dec_and_test (&block_notifications)) {
333 flush_notifications ();
339 Playlist::notify_modified ()
341 if (holding_state ()) {
342 pending_modified = true;
344 pending_modified = false;
345 Modified(); /* EMIT SIGNAL */
350 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
352 if (holding_state ()) {
353 pending_removes.insert (r);
354 pending_modified = true;
355 pending_length = true;
357 /* this might not be true, but we have to act
358 as though it could be.
360 LengthChanged (); /* EMIT SIGNAL */
361 Modified (); /* EMIT SIGNAL */
366 Playlist::notify_region_added (boost::shared_ptr<Region> r)
368 /* the length change might not be true, but we have to act
369 as though it could be.
372 if (holding_state()) {
373 pending_adds.insert (r);
374 pending_modified = true;
375 pending_length = true;
377 LengthChanged (); /* EMIT SIGNAL */
378 Modified (); /* EMIT SIGNAL */
383 Playlist::notify_length_changed ()
385 if (holding_state ()) {
386 pending_length = true;
388 LengthChanged(); /* EMIT SIGNAL */
389 Modified (); /* EMIT SIGNAL */
394 Playlist::flush_notifications ()
396 set<boost::shared_ptr<Region> > dependent_checks_needed;
397 set<boost::shared_ptr<Region> >::iterator s;
406 /* we have no idea what order the regions ended up in pending
407 bounds (it could be based on selection order, for example).
408 so, to preserve layering in the "most recently moved is higher"
409 model, sort them by existing layer, then timestamp them.
412 // RegionSortByLayer cmp;
413 // pending_bounds.sort (cmp);
415 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
416 if (Config->get_layer_model() == MoveAddHigher) {
417 timestamp_layer_op (*r);
419 pending_length = true;
420 dependent_checks_needed.insert (*r);
424 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
425 dependent_checks_needed.insert (*s);
429 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
430 remove_dependents (*s);
434 if ((freeze_length != _get_maximum_extent()) || pending_length) {
436 LengthChanged(); /* EMIT SIGNAL */
440 if (n || pending_modified) {
444 pending_modified = false;
445 Modified (); /* EMIT SIGNAL */
448 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
449 check_dependents (*s, false);
452 pending_adds.clear ();
453 pending_removes.clear ();
454 pending_bounds.clear ();
459 /*************************************************************
461 *************************************************************/
464 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times)
466 RegionLock rlock (this);
468 times = fabs (times);
470 int itimes = (int) floor (times);
472 nframes_t pos = position;
475 add_region_internal (region, pos);
476 pos += region->length();
481 /* note that itimes can be zero if we being asked to just
482 insert a single fraction of the region.
485 for (int i = 0; i < itimes; ++i) {
486 boost::shared_ptr<Region> copy = RegionFactory::create (region);
487 add_region_internal (copy, pos);
488 pos += region->length();
491 nframes_t length = 0;
493 if (floor (times) != times) {
494 length = (nframes_t) floor (region->length() * (times - floor (times)));
496 _session.region_name (name, region->name(), false);
497 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
498 add_region_internal (sub, pos);
502 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
506 Playlist::set_region_ownership ()
508 RegionLock rl (this);
509 RegionList::iterator i;
510 boost::weak_ptr<Playlist> pl (shared_from_this());
512 for (i = regions.begin(); i != regions.end(); ++i) {
513 (*i)->set_playlist (pl);
518 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
520 RegionSortByPosition cmp;
521 nframes_t old_length = 0;
523 if (!holding_state()) {
524 old_length = _get_maximum_extent();
527 if (!first_set_state) {
528 boost::shared_ptr<Playlist> foo (shared_from_this());
529 region->set_playlist (boost::weak_ptr<Playlist>(foo));
532 region->set_position (position, this);
534 timestamp_layer_op (region);
536 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
537 all_regions.insert (region);
539 possibly_splice_unlocked (position, region->length(), region);
541 if (!holding_state () && !in_set_state) {
542 /* layers get assigned from XML state */
546 /* we need to notify the existence of new region before checking dependents. Ick. */
548 notify_region_added (region);
550 if (!holding_state ()) {
551 check_dependents (region, false);
552 if (old_length != _get_maximum_extent()) {
553 notify_length_changed ();
557 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
558 boost::weak_ptr<Region> (region)));
562 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
564 RegionLock rlock (this);
566 bool old_sp = _splicing;
569 remove_region_internal (old);
570 add_region_internal (newr, pos);
574 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
578 Playlist::remove_region (boost::shared_ptr<Region> region)
580 RegionLock rlock (this);
581 remove_region_internal (region);
585 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
587 RegionList::iterator i;
588 nframes_t old_length = 0;
590 if (!holding_state()) {
591 old_length = _get_maximum_extent();
596 region->set_playlist (boost::weak_ptr<Playlist>());
599 for (i = regions.begin(); i != regions.end(); ++i) {
602 nframes_t pos = (*i)->position();
603 nframes64_t distance = (*i)->length();
607 possibly_splice_unlocked (pos, -distance);
609 if (!holding_state ()) {
611 remove_dependents (region);
613 if (old_length != _get_maximum_extent()) {
614 notify_length_changed ();
618 notify_region_removed (region);
629 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
631 if (Config->get_use_overlap_equivalency()) {
632 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
633 if ((*i)->overlap_equivalent (other)) {
634 results.push_back ((*i));
638 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
639 if ((*i)->equivalent (other)) {
640 results.push_back ((*i));
647 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
649 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
651 if ((*i) && (*i)->region_list_equivalent (other)) {
652 results.push_back (*i);
658 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
662 partition_internal (start, end, false, thawlist);
664 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
665 (*i)->thaw ("separation");
670 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
672 RegionList new_regions;
675 RegionLock rlock (this);
676 boost::shared_ptr<Region> region;
677 boost::shared_ptr<Region> current;
679 RegionList::iterator tmp;
681 nframes_t pos1, pos2, pos3, pos4;
685 /* need to work from a copy, because otherwise the regions we add during the process
686 get operated on as well.
689 RegionList copy = regions;
691 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
698 if (current->first_frame() == start && current->last_frame() == end) {
700 remove_region_internal (current);
705 if ((overlap = current->coverage (start, end)) == OverlapNone) {
709 pos1 = current->position();
712 pos4 = current->last_frame();
714 if (overlap == OverlapInternal) {
716 /* split: we need 3 new regions, the front, middle and end.
717 cut: we need 2 regions, the front and end.
722 ---------------*************************------------
725 ---------------*****++++++++++++++++====------------
727 ---------------*****----------------====------------
733 /* "middle" ++++++ */
735 _session.region_name (new_name, current->name(), false);
736 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
737 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
738 add_region_internal (region, start);
739 new_regions.push_back (region);
744 _session.region_name (new_name, current->name(), false);
745 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
746 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
748 add_region_internal (region, end);
749 new_regions.push_back (region);
754 thawlist.push_back (current);
755 current->trim_end (pos2, this);
757 } else if (overlap == OverlapEnd) {
761 ---------------*************************------------
764 ---------------**************+++++++++++------------
766 ---------------**************-----------------------
773 _session.region_name (new_name, current->name(), false);
774 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
775 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
776 add_region_internal (region, start);
777 new_regions.push_back (region);
783 thawlist.push_back (current);
784 current->trim_end (pos2, this);
786 } else if (overlap == OverlapStart) {
788 /* split: we need 2 regions: the front and the end.
789 cut: just trim current to skip the cut area
794 ---------------*************************------------
798 ---------------****+++++++++++++++++++++------------
800 -------------------*********************------------
807 _session.region_name (new_name, current->name(), false);
808 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
809 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
810 add_region_internal (region, pos1);
811 new_regions.push_back (region);
817 thawlist.push_back (current);
818 current->trim_front (pos3, this);
820 } else if (overlap == OverlapExternal) {
822 /* split: no split required.
823 cut: remove the region.
828 ---------------*************************------------
832 ---------------*************************------------
834 ----------------------------------------------------
839 remove_region_internal (current);
841 new_regions.push_back (current);
845 in_partition = false;
848 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
849 check_dependents (*i, false);
853 boost::shared_ptr<Playlist>
854 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
856 boost::shared_ptr<Playlist> ret;
857 boost::shared_ptr<Playlist> pl;
860 if (ranges.empty()) {
861 return boost::shared_ptr<Playlist>();
864 start = ranges.front().start;
866 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
868 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
870 if (i == ranges.begin()) {
874 /* paste the next section into the nascent playlist,
875 offset to reflect the start of the first range we
879 ret->paste (pl, (*i).start - start, 1.0f);
886 boost::shared_ptr<Playlist>
887 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
889 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
890 return cut_copy (pmf, ranges, result_is_hidden);
893 boost::shared_ptr<Playlist>
894 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
896 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
897 return cut_copy (pmf, ranges, result_is_hidden);
900 boost::shared_ptr<Playlist>
901 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
903 boost::shared_ptr<Playlist> the_copy;
907 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
908 string new_name = _name;
912 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
913 return boost::shared_ptr<Playlist>();
916 partition_internal (start, start+cnt-1, true, thawlist);
918 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
919 (*i)->thaw ("playlist cut");
925 boost::shared_ptr<Playlist>
926 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
930 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
931 string new_name = _name;
935 cnt = min (_get_maximum_extent() - start, cnt);
936 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
940 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
942 times = fabs (times);
943 nframes_t old_length;
946 RegionLock rl1 (this);
947 RegionLock rl2 (other.get());
949 old_length = _get_maximum_extent();
951 int itimes = (int) floor (times);
952 nframes_t pos = position;
953 nframes_t shift = other->_get_maximum_extent();
954 layer_t top_layer = regions.size();
957 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
958 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
960 /* put these new regions on top of all existing ones, but preserve
961 the ordering they had in the original playlist.
964 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
965 add_region_internal (copy_of_region, copy_of_region->position() + pos);
971 /* XXX shall we handle fractional cases at some point? */
973 if (old_length != _get_maximum_extent()) {
974 notify_length_changed ();
985 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
987 times = fabs (times);
989 RegionLock rl (this);
990 int itimes = (int) floor (times);
991 nframes_t pos = position;
994 boost::shared_ptr<Region> copy = RegionFactory::create (region);
995 add_region_internal (copy, pos);
996 pos += region->length();
999 if (floor (times) != times) {
1000 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1002 _session.region_name (name, region->name(), false);
1003 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1004 add_region_internal (sub, pos);
1009 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1011 RegionLock rl (this);
1013 if (!region->covers (playlist_position)) {
1017 if (region->position() == playlist_position ||
1018 region->last_frame() == playlist_position) {
1022 boost::shared_ptr<Region> left;
1023 boost::shared_ptr<Region> right;
1029 /* split doesn't change anything about length, so don't try to splice */
1031 bool old_sp = _splicing;
1034 before = playlist_position - region->position();
1035 after = region->length() - before;
1037 _session.region_name (before_name, region->name(), false);
1038 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1040 _session.region_name (after_name, region->name(), false);
1041 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1043 add_region_internal (left, region->position());
1044 add_region_internal (right, region->position() + before);
1046 uint64_t orig_layer_op = region->last_layer_op();
1047 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1048 if ((*i)->last_layer_op() > orig_layer_op) {
1049 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1053 left->set_last_layer_op ( orig_layer_op );
1054 right->set_last_layer_op ( orig_layer_op + 1);
1058 finalize_split_region (region, left, right);
1060 remove_region_internal (region);
1066 Playlist::possibly_splice (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_locked (at, distance, exclude);
1079 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1081 if (_splicing || in_set_state) {
1082 /* don't respond to splicing moves or state setting */
1086 if (_edit_mode == Splice) {
1087 splice_unlocked (at, distance, exclude);
1092 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1095 RegionLock rl (this);
1096 core_splice (at, distance, exclude);
1101 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1103 core_splice (at, distance, exclude);
1107 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1111 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1113 if (exclude && (*i) == exclude) {
1117 if ((*i)->position() >= at) {
1118 nframes64_t new_pos = (*i)->position() + distance;
1121 } else if (new_pos >= max_frames - (*i)->length()) {
1122 new_pos = max_frames - (*i)->length();
1125 (*i)->set_position (new_pos, this);
1131 notify_length_changed ();
1135 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1137 if (in_set_state || _splicing || _nudging || _shuffling) {
1141 if (what_changed & ARDOUR::PositionChanged) {
1143 /* remove it from the list then add it back in
1144 the right place again.
1147 RegionSortByPosition cmp;
1149 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1151 if (i == regions.end()) {
1152 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1153 _name, region->name())
1159 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1162 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1164 nframes64_t delta = 0;
1166 if (what_changed & ARDOUR::PositionChanged) {
1167 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1170 if (what_changed & ARDOUR::LengthChanged) {
1171 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1175 possibly_splice (region->last_position() + region->last_length(), delta, region);
1178 if (holding_state ()) {
1179 pending_bounds.push_back (region);
1181 if (Config->get_layer_model() == MoveAddHigher) {
1182 /* it moved or changed length, so change the timestamp */
1183 timestamp_layer_op (region);
1186 notify_length_changed ();
1188 check_dependents (region, false);
1194 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1196 boost::shared_ptr<Region> region (weak_region.lock());
1203 /* this makes a virtual call to the right kind of playlist ... */
1205 region_changed (what_changed, region);
1209 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1211 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1214 if (in_set_state || in_flush) {
1219 if (what_changed & BoundsChanged) {
1220 region_bounds_changed (what_changed, region);
1221 save = !(_splicing || _nudging);
1224 if ((what_changed & our_interests) &&
1225 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1226 check_dependents (region, false);
1229 if (what_changed & our_interests) {
1238 Playlist::drop_regions ()
1240 RegionLock rl (this);
1242 all_regions.clear ();
1246 Playlist::clear (bool with_signals)
1249 RegionLock rl (this);
1250 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1251 pending_removes.insert (*i);
1263 /***********************************************************************
1265 **********************************************************************/
1267 Playlist::RegionList *
1268 Playlist::regions_at (nframes_t frame)
1271 RegionLock rlock (this);
1272 return find_regions_at (frame);
1275 boost::shared_ptr<Region>
1276 Playlist::top_region_at (nframes_t frame)
1279 RegionLock rlock (this);
1280 RegionList *rlist = find_regions_at (frame);
1281 boost::shared_ptr<Region> region;
1283 if (rlist->size()) {
1284 RegionSortByLayer cmp;
1286 region = rlist->back();
1293 Playlist::RegionList*
1294 Playlist::regions_to_read (nframes_t start, nframes_t end)
1296 /* Caller must hold lock */
1298 RegionList covering;
1299 set<nframes_t> to_check;
1300 set<boost::shared_ptr<Region> > unique;
1303 to_check.insert (start);
1304 to_check.insert (end);
1306 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1308 /* find all/any regions that span start+end */
1310 switch ((*i)->coverage (start, end)) {
1314 case OverlapInternal:
1315 covering.push_back (*i);
1319 to_check.insert ((*i)->position());
1320 covering.push_back (*i);
1324 to_check.insert ((*i)->last_frame());
1325 covering.push_back (*i);
1328 case OverlapExternal:
1329 covering.push_back (*i);
1330 to_check.insert ((*i)->position());
1331 to_check.insert ((*i)->last_frame());
1335 /* don't go too far */
1337 if ((*i)->position() > end) {
1342 RegionList* rlist = new RegionList;
1344 /* find all the regions that cover each position .... */
1346 if (covering.size() == 1) {
1348 rlist->push_back (covering.front());
1352 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1356 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1358 if ((*x)->covers (*t)) {
1359 here.push_back (*x);
1363 RegionSortByLayer cmp;
1366 /* ... and get the top/transparent regions at "here" */
1368 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1372 if ((*c)->opaque()) {
1374 /* the other regions at this position are hidden by this one */
1381 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1382 rlist->push_back (*s);
1385 if (rlist->size() > 1) {
1386 /* now sort by time order */
1388 RegionSortByPosition cmp;
1396 Playlist::RegionList *
1397 Playlist::find_regions_at (nframes_t frame)
1399 /* Caller must hold lock */
1401 RegionList *rlist = new RegionList;
1403 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1404 if ((*i)->covers (frame)) {
1405 rlist->push_back (*i);
1412 Playlist::RegionList *
1413 Playlist::regions_touched (nframes_t start, nframes_t end)
1415 RegionLock rlock (this);
1416 RegionList *rlist = new RegionList;
1418 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1419 if ((*i)->coverage (start, end) != OverlapNone) {
1420 rlist->push_back (*i);
1428 Playlist::find_next_transient (nframes64_t from, int dir)
1430 RegionLock rlock (this);
1431 AnalysisFeatureList points;
1432 AnalysisFeatureList these_points;
1434 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1436 if ((*i)->last_frame() < from) {
1440 if ((*i)->first_frame() > from) {
1445 (*i)->get_transients (these_points);
1447 /* add first frame, just, err, because */
1449 these_points.push_back ((*i)->first_frame());
1451 points.insert (points.end(), these_points.begin(), these_points.end());
1452 these_points.clear ();
1455 if (points.empty()) {
1459 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1460 bool reached = false;
1463 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1468 if (reached && (*x) > from) {
1473 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1478 if (reached && (*x) < from) {
1487 boost::shared_ptr<Region>
1488 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1490 RegionLock rlock (this);
1491 boost::shared_ptr<Region> ret;
1492 nframes_t closest = max_frames;
1495 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1498 boost::shared_ptr<Region> r = (*i);
1503 pos = r->first_frame ();
1506 pos = r->last_frame ();
1509 pos = r->adjust_to_sync (r->first_frame());
1514 case 1: /* forwards */
1517 if ((distance = pos - frame) < closest) {
1525 default: /* backwards */
1528 if ((distance = frame - pos) < closest) {
1541 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1543 RegionLock rlock (this);
1545 nframes64_t closest = max_frames;
1546 nframes64_t ret = -1;
1550 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1552 boost::shared_ptr<Region> r = (*i);
1553 nframes64_t distance;
1554 nframes64_t end = r->position() + r->length();
1559 if (r->first_frame() > frame) {
1561 distance = r->first_frame() - frame;
1563 if (distance < closest) {
1564 ret = r->first_frame();
1572 distance = end - frame;
1574 if (distance < closest) {
1588 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1590 boost::shared_ptr<Region> r = (*i);
1591 nframes64_t distance;
1596 if (r->last_frame() < frame) {
1598 distance = frame - r->last_frame();
1600 if (distance < closest) {
1601 ret = r->last_frame();
1607 if (r->first_frame() < frame) {
1608 distance = frame - r->last_frame();
1610 if (distance < closest) {
1611 ret = r->first_frame();
1626 /***********************************************************************/
1631 Playlist::mark_session_dirty ()
1633 if (!in_set_state && !holding_state ()) {
1634 _session.set_dirty();
1639 Playlist::set_state (const XMLNode& node)
1643 XMLNodeConstIterator niter;
1644 XMLPropertyList plist;
1645 XMLPropertyConstIterator piter;
1647 boost::shared_ptr<Region> region;
1652 if (node.name() != "Playlist") {
1659 plist = node.properties();
1661 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1665 if (prop->name() == X_("name")) {
1666 _name = prop->value();
1667 } else if (prop->name() == X_("orig_diskstream_id")) {
1668 _orig_diskstream_id = prop->value ();
1669 } else if (prop->name() == X_("frozen")) {
1670 _frozen = (prop->value() == X_("yes"));
1676 nlist = node.children();
1678 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1682 if (child->name() == "Region") {
1684 if ((prop = child->property ("id")) == 0) {
1685 error << _("region state node has no ID, ignored") << endmsg;
1689 ID id = prop->value ();
1691 if ((region = region_by_id (id))) {
1693 Change what_changed = Change (0);
1695 if (region->set_live_state (*child, what_changed, true)) {
1696 error << _("Playlist: cannot reset region state from XML") << endmsg;
1700 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1701 error << _("Playlist: cannot create region from XML") << endmsg;
1705 add_region (region, region->position(), 1.0);
1707 // So that layer_op ordering doesn't get screwed up
1708 region->set_last_layer_op( region->layer());
1717 /* update dependents, which was not done during add_region_internal
1718 due to in_set_state being true
1721 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1722 check_dependents (*r, false);
1726 first_set_state = false;
1731 Playlist::get_state()
1737 Playlist::get_template()
1739 return state(false);
1743 Playlist::state (bool full_state)
1745 XMLNode *node = new XMLNode (X_("Playlist"));
1748 node->add_property (X_("name"), _name);
1750 _orig_diskstream_id.print (buf, sizeof (buf));
1751 node->add_property (X_("orig_diskstream_id"), buf);
1752 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1755 RegionLock rlock (this, false);
1756 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1757 node->add_child_nocopy ((*i)->get_state());
1762 node->add_child_copy (*_extra_xml);
1769 Playlist::empty() const
1771 RegionLock rlock (const_cast<Playlist *>(this), false);
1772 return regions.empty();
1776 Playlist::n_regions() const
1778 RegionLock rlock (const_cast<Playlist *>(this), false);
1779 return regions.size();
1783 Playlist::get_maximum_extent () const
1785 RegionLock rlock (const_cast<Playlist *>(this), false);
1786 return _get_maximum_extent ();
1790 Playlist::_get_maximum_extent () const
1792 RegionList::const_iterator i;
1793 nframes_t max_extent = 0;
1796 for (i = regions.begin(); i != regions.end(); ++i) {
1797 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1806 Playlist::bump_name (string name, Session &session)
1808 string newname = name;
1811 newname = bump_name_once (newname);
1812 } while (session.playlist_by_name (newname)!=NULL);
1819 Playlist::top_layer() const
1821 RegionLock rlock (const_cast<Playlist *> (this));
1824 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1825 top = max (top, (*i)->layer());
1831 Playlist::set_edit_mode (EditMode mode)
1836 /********************
1838 ********************/
1841 Playlist::relayer ()
1843 RegionList::iterator i;
1846 /* don't send multiple Modified notifications
1847 when multiple regions are relayered.
1852 if (Config->get_layer_model() == MoveAddHigher ||
1853 Config->get_layer_model() == AddHigher) {
1855 RegionSortByLastLayerOp cmp;
1856 RegionList copy = regions;
1860 for (i = copy.begin(); i != copy.end(); ++i) {
1861 (*i)->set_layer (layer++);
1866 /* Session::LaterHigher model */
1868 for (i = regions.begin(); i != regions.end(); ++i) {
1869 (*i)->set_layer (layer++);
1873 /* sending Modified means that various kinds of layering
1874 models operate correctly at the GUI
1875 level. slightly inefficient, but only slightly.
1877 We force a Modified signal here in case no layers actually
1886 /* XXX these layer functions are all deprecated */
1889 Playlist::raise_region (boost::shared_ptr<Region> region)
1891 uint32_t rsz = regions.size();
1892 layer_t target = region->layer() + 1U;
1894 if (target >= rsz) {
1895 /* its already at the effective top */
1899 move_region_to_layer (target, region, 1);
1903 Playlist::lower_region (boost::shared_ptr<Region> region)
1905 if (region->layer() == 0) {
1906 /* its already at the bottom */
1910 layer_t target = region->layer() - 1U;
1912 move_region_to_layer (target, region, -1);
1916 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
1918 /* does nothing useful if layering mode is later=higher */
1919 if ((Config->get_layer_model() == MoveAddHigher) ||
1920 (Config->get_layer_model() == AddHigher)) {
1921 timestamp_layer_op (region);
1927 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
1929 /* does nothing useful if layering mode is later=higher */
1930 if ((Config->get_layer_model() == MoveAddHigher) ||
1931 (Config->get_layer_model() == AddHigher)) {
1932 region->set_last_layer_op (0);
1938 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
1940 RegionList::iterator i;
1941 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
1942 list<LayerInfo> layerinfo;
1946 RegionLock rlock (const_cast<Playlist *> (this));
1948 for (i = regions.begin(); i != regions.end(); ++i) {
1956 /* region is moving up, move all regions on intermediate layers
1960 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
1961 dest = (*i)->layer() - 1;
1968 /* region is moving down, move all regions on intermediate layers
1972 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
1973 dest = (*i)->layer() + 1;
1983 newpair.second = dest;
1985 layerinfo.push_back (newpair);
1989 /* now reset the layers without holding the region lock */
1991 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1992 x->first->set_layer (x->second);
1995 region->set_layer (target_layer);
1998 /* now check all dependents */
2000 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2001 check_dependents (x->first, false);
2004 check_dependents (region, false);
2011 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2013 RegionList::iterator i;
2020 RegionLock rlock (const_cast<Playlist *> (this));
2022 for (i = regions.begin(); i != regions.end(); ++i) {
2024 if ((*i)->position() >= start) {
2028 if ((*i)->last_frame() > max_frames - distance) {
2029 new_pos = max_frames - (*i)->length();
2031 new_pos = (*i)->position() + distance;
2036 if ((*i)->position() > distance) {
2037 new_pos = (*i)->position() - distance;
2043 (*i)->set_position (new_pos, this);
2051 notify_length_changed ();
2056 boost::shared_ptr<Region>
2057 Playlist::find_region (const ID& id) const
2059 RegionLock rlock (const_cast<Playlist*> (this));
2061 /* searches all regions currently in use by the playlist */
2063 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2064 if ((*i)->id() == id) {
2069 return boost::shared_ptr<Region> ();
2072 boost::shared_ptr<Region>
2073 Playlist::region_by_id (ID id)
2075 /* searches all regions ever added to this playlist */
2077 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2078 if ((*i)->id() == id) {
2082 return boost::shared_ptr<Region> ();
2086 Playlist::dump () const
2088 boost::shared_ptr<Region> r;
2090 cerr << "Playlist \"" << _name << "\" " << endl
2091 << regions.size() << " regions "
2094 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2096 cerr << " " << r->name() << " ["
2097 << r->start() << "+" << r->length()
2107 Playlist::set_frozen (bool yn)
2113 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2115 // struct timeval tv;
2116 // gettimeofday (&tv, 0);
2117 region->set_last_layer_op (++layer_op_counter);
2122 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2127 if (region->locked()) {
2134 RegionLock rlock (const_cast<Playlist*> (this));
2139 RegionList::iterator next;
2141 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2142 if ((*i) == region) {
2146 if (next != regions.end()) {
2148 if ((*next)->locked()) {
2152 if ((*next)->position() != region->last_frame() + 1) {
2153 /* they didn't used to touch, so after shuffle,
2154 just have them swap positions.
2156 new_pos = (*next)->position();
2158 /* they used to touch, so after shuffle,
2159 make sure they still do. put the earlier
2160 region where the later one will end after
2163 new_pos = region->position() + (*next)->length();
2166 (*next)->set_position (region->position(), this);
2167 region->set_position (new_pos, this);
2169 /* avoid a full sort */
2171 regions.erase (i); // removes the region from the list */
2173 regions.insert (next, region); // adds it back after next
2182 RegionList::iterator prev = regions.end();
2184 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2185 if ((*i) == region) {
2187 if (prev != regions.end()) {
2189 if ((*prev)->locked()) {
2193 if (region->position() != (*prev)->last_frame() + 1) {
2194 /* they didn't used to touch, so after shuffle,
2195 just have them swap positions.
2197 new_pos = region->position();
2199 /* they used to touch, so after shuffle,
2200 make sure they still do. put the earlier
2201 one where the later one will end after
2203 new_pos = (*prev)->position() + region->length();
2206 region->set_position ((*prev)->position(), this);
2207 (*prev)->set_position (new_pos, this);
2209 /* avoid a full sort */
2211 regions.erase (i); // remove region
2212 regions.insert (prev, region); // insert region before prev
2228 check_dependents (region, false);
2236 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2238 RegionLock rlock (const_cast<Playlist*> (this));
2240 if (regions.size() > 1) {
2248 Playlist::update_after_tempo_map_change ()
2250 RegionLock rlock (const_cast<Playlist*> (this));
2251 RegionList copy (regions);
2255 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2256 (*i)->update_position_after_tempo_map_change ();