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();
76 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
77 : SessionObject(sess, nom)
81 first_set_state = false;
86 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
87 : SessionObject(sess, "unnamed playlist")
90 const XMLProperty* prop = node.property("type");
91 assert(!prop || DataType(prop->value()) == _type);
94 _name = "unnamed"; /* reset by set_state */
96 /* set state called by derived class */
99 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
100 : SessionObject(other->_session, namestr), _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());
115 _splicing = other->_splicing;
116 _nudging = other->_nudging;
117 _edit_mode = other->_edit_mode;
120 first_set_state = false;
122 in_partition = false;
124 _read_data_count = 0;
125 _frozen = other->_frozen;
127 layer_op_counter = other->layer_op_counter;
128 freeze_length = other->freeze_length;
131 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
132 : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
134 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
136 nframes_t end = start + cnt - 1;
142 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
144 boost::shared_ptr<Region> region;
145 boost::shared_ptr<Region> new_region;
146 nframes_t offset = 0;
147 nframes_t position = 0;
154 overlap = region->coverage (start, end);
160 case OverlapInternal:
161 offset = start - region->position();
168 position = region->position() - start;
169 len = end - region->position();
173 offset = start - region->position();
175 len = region->length() - offset;
178 case OverlapExternal:
180 position = region->position() - start;
181 len = region->length();
185 _session.region_name (new_name, region->name(), false);
187 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
189 add_region_internal (new_region, position);
193 first_set_state = false;
195 /* this constructor does NOT notify others (session) */
202 InUse (true); /* EMIT SIGNAL */
213 InUse (false); /* EMIT SIGNAL */
218 Playlist::copy_regions (RegionList& newlist) const
220 RegionLock rlock (const_cast<Playlist *> (this));
222 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
223 newlist.push_back (RegionFactory::RegionFactory::create (*i));
228 Playlist::init (bool hide)
230 g_atomic_int_set (&block_notifications, 0);
231 g_atomic_int_set (&ignore_state_changes, 0);
232 pending_modified = false;
233 pending_length = false;
234 first_set_state = true;
241 _edit_mode = Config->get_edit_mode();
243 in_partition = false;
245 _read_data_count = 0;
247 layer_op_counter = 0;
250 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
253 Playlist::~Playlist ()
256 RegionLock rl (this);
258 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
259 (*i)->set_playlist (boost::shared_ptr<Playlist>());
263 /* GoingAway must be emitted by derived classes */
267 Playlist::set_name (const string& str)
269 /* in a typical situation, a playlist is being used
270 by one diskstream and also is referenced by the
271 Session. if there are more references than that,
272 then don't change the name.
278 return SessionObject::set_name(str);
282 /***********************************************************************
283 CHANGE NOTIFICATION HANDLING
285 Notifications must be delayed till the region_lock is released. This
286 is necessary because handlers for the signals may need to acquire
287 the lock (e.g. to read from the playlist).
288 ***********************************************************************/
293 delay_notifications ();
294 g_atomic_int_inc (&ignore_state_changes);
300 g_atomic_int_dec_and_test (&ignore_state_changes);
301 release_notifications ();
306 Playlist::delay_notifications ()
308 g_atomic_int_inc (&block_notifications);
309 freeze_length = _get_maximum_extent();
313 Playlist::release_notifications ()
315 if (g_atomic_int_dec_and_test (&block_notifications)) {
316 flush_notifications ();
321 Playlist::notify_modified ()
323 if (holding_state ()) {
324 pending_modified = true;
326 pending_modified = false;
327 Modified(); /* EMIT SIGNAL */
332 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
334 if (holding_state ()) {
335 pending_removes.insert (r);
336 pending_modified = true;
337 pending_length = true;
339 /* this might not be true, but we have to act
340 as though it could be.
342 pending_length = false;
343 LengthChanged (); /* EMIT SIGNAL */
344 pending_modified = false;
345 Modified (); /* EMIT SIGNAL */
350 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
352 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
354 if (holding_state ()) {
356 pending_range_moves.push_back (move);
360 list< Evoral::RangeMove<nframes_t> > m;
369 Playlist::notify_region_added (boost::shared_ptr<Region> r)
371 /* the length change might not be true, but we have to act
372 as though it could be.
375 if (holding_state()) {
376 pending_adds.insert (r);
377 pending_modified = true;
378 pending_length = true;
380 pending_length = false;
381 LengthChanged (); /* EMIT SIGNAL */
382 pending_modified = false;
383 Modified (); /* EMIT SIGNAL */
388 Playlist::notify_length_changed ()
390 if (holding_state ()) {
391 pending_length = true;
393 pending_length = false;
394 LengthChanged(); /* EMIT SIGNAL */
395 pending_modified = false;
396 Modified (); /* EMIT SIGNAL */
401 Playlist::flush_notifications ()
403 set<boost::shared_ptr<Region> > dependent_checks_needed;
404 set<boost::shared_ptr<Region> >::iterator s;
413 /* we have no idea what order the regions ended up in pending
414 bounds (it could be based on selection order, for example).
415 so, to preserve layering in the "most recently moved is higher"
416 model, sort them by existing layer, then timestamp them.
419 // RegionSortByLayer cmp;
420 // pending_bounds.sort (cmp);
422 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
423 if (Config->get_layer_model() == MoveAddHigher) {
424 timestamp_layer_op (*r);
426 pending_length = true;
427 dependent_checks_needed.insert (*r);
431 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
432 dependent_checks_needed.insert (*s);
436 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
437 remove_dependents (*s);
441 if ((freeze_length != _get_maximum_extent()) || pending_length) {
443 LengthChanged(); /* EMIT SIGNAL */
447 if (n || pending_modified) {
451 pending_modified = false;
452 Modified (); /* EMIT SIGNAL */
456 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
457 check_dependents (*s, false);
460 if (!pending_range_moves.empty ()) {
461 RangesMoved (pending_range_moves);
464 pending_adds.clear ();
465 pending_removes.clear ();
466 pending_bounds.clear ();
467 pending_range_moves.clear ();
472 /*************************************************************
474 *************************************************************/
477 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
479 RegionLock rlock (this);
480 times = fabs (times);
482 int itimes = (int) floor (times);
484 nframes_t pos = position;
486 if(times == 1 && auto_partition){
487 partition(pos, (nframes_t) (pos + region->length()), true);
491 add_region_internal (region, pos);
492 pos += region->length();
497 /* note that itimes can be zero if we being asked to just
498 insert a single fraction of the region.
501 for (int i = 0; i < itimes; ++i) {
502 boost::shared_ptr<Region> copy = RegionFactory::create (region);
503 add_region_internal (copy, pos);
504 pos += region->length();
507 nframes_t length = 0;
509 if (floor (times) != times) {
510 length = (nframes_t) floor (region->length() * (times - floor (times)));
512 _session.region_name (name, region->name(), false);
513 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
514 add_region_internal (sub, pos);
517 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
521 Playlist::set_region_ownership ()
523 RegionLock rl (this);
524 RegionList::iterator i;
525 boost::weak_ptr<Playlist> pl (shared_from_this());
527 for (i = regions.begin(); i != regions.end(); ++i) {
528 (*i)->set_playlist (pl);
533 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
535 if (region->data_type() != _type){
539 RegionSortByPosition cmp;
540 nframes_t old_length = 0;
542 if (!holding_state()) {
543 old_length = _get_maximum_extent();
546 if (!first_set_state) {
547 boost::shared_ptr<Playlist> foo (shared_from_this());
548 region->set_playlist (boost::weak_ptr<Playlist>(foo));
551 region->set_position (position, this);
553 timestamp_layer_op (region);
555 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
556 all_regions.insert (region);
558 possibly_splice_unlocked (position, region->length(), region);
560 if (!holding_state () && !in_set_state) {
561 /* layers get assigned from XML state */
565 /* we need to notify the existence of new region before checking dependents. Ick. */
567 notify_region_added (region);
569 if (!holding_state ()) {
570 check_dependents (region, false);
571 if (old_length != _get_maximum_extent()) {
572 notify_length_changed ();
576 region_state_changed_connections.push_back (
577 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
578 boost::weak_ptr<Region> (region)))
585 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
587 RegionLock rlock (this);
589 bool old_sp = _splicing;
592 remove_region_internal (old);
593 add_region_internal (newr, pos);
597 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
601 Playlist::remove_region (boost::shared_ptr<Region> region)
603 RegionLock rlock (this);
604 remove_region_internal (region);
608 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
610 RegionList::iterator i;
611 nframes_t old_length = 0;
613 if (!holding_state()) {
614 old_length = _get_maximum_extent();
619 region->set_playlist (boost::weak_ptr<Playlist>());
622 for (i = regions.begin(); i != regions.end(); ++i) {
625 nframes_t pos = (*i)->position();
626 nframes64_t distance = (*i)->length();
630 possibly_splice_unlocked (pos, -distance);
632 if (!holding_state ()) {
634 remove_dependents (region);
636 if (old_length != _get_maximum_extent()) {
637 notify_length_changed ();
641 notify_region_removed (region);
652 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
654 if (Config->get_use_overlap_equivalency()) {
655 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
656 if ((*i)->overlap_equivalent (other)) {
657 results.push_back ((*i));
661 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
662 if ((*i)->equivalent (other)) {
663 results.push_back ((*i));
670 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
672 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
674 if ((*i) && (*i)->region_list_equivalent (other)) {
675 results.push_back (*i);
681 Playlist::partition (nframes_t start, nframes_t end, bool cut)
685 partition_internal (start, end, cut, thawlist);
687 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
688 (*i)->thaw ("separation");
693 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
695 RegionList new_regions;
698 RegionLock rlock (this);
700 boost::shared_ptr<Region> region;
701 boost::shared_ptr<Region> current;
703 RegionList::iterator tmp;
705 nframes_t pos1, pos2, pos3, pos4;
709 /* need to work from a copy, because otherwise the regions we add during the process
710 get operated on as well.
713 RegionList copy = regions;
715 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
722 if (current->first_frame() >= start && current->last_frame() < end) {
725 remove_region_internal (current);
731 /* coverage will return OverlapStart if the start coincides
732 with the end point. we do not partition such a region,
733 so catch this special case.
736 if (current->first_frame() >= end) {
740 if ((overlap = current->coverage (start, end)) == OverlapNone) {
744 pos1 = current->position();
747 pos4 = current->last_frame();
749 if (overlap == OverlapInternal) {
750 /* split: we need 3 new regions, the front, middle and end.
751 cut: we need 2 regions, the front and end.
756 ---------------*************************------------
759 ---------------*****++++++++++++++++====------------
761 ---------------*****----------------====------------
766 /* "middle" ++++++ */
768 _session.region_name (new_name, current->name(), false);
769 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
770 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
771 add_region_internal (region, start);
772 new_regions.push_back (region);
777 _session.region_name (new_name, current->name(), false);
778 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
779 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
781 add_region_internal (region, end);
782 new_regions.push_back (region);
787 thawlist.push_back (current);
788 current->trim_end (pos2, this);
790 } else if (overlap == OverlapEnd) {
794 ---------------*************************------------
797 ---------------**************+++++++++++------------
799 ---------------**************-----------------------
806 _session.region_name (new_name, current->name(), false);
807 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
808 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
810 add_region_internal (region, start);
811 new_regions.push_back (region);
817 thawlist.push_back (current);
818 current->trim_end (pos2, this);
820 } else if (overlap == OverlapStart) {
822 /* split: we need 2 regions: the front and the end.
823 cut: just trim current to skip the cut area
828 ---------------*************************------------
832 ---------------****+++++++++++++++++++++------------
834 -------------------*********************------------
840 _session.region_name (new_name, current->name(), false);
841 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
842 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
844 add_region_internal (region, pos1);
845 new_regions.push_back (region);
851 thawlist.push_back (current);
852 current->trim_front (pos3, this);
853 } else if (overlap == OverlapExternal) {
855 /* split: no split required.
856 cut: remove the region.
861 ---------------*************************------------
865 ---------------*************************------------
867 ----------------------------------------------------
872 remove_region_internal (current);
875 new_regions.push_back (current);
879 in_partition = false;
882 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
883 check_dependents (*i, false);
887 boost::shared_ptr<Playlist>
888 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
890 boost::shared_ptr<Playlist> ret;
891 boost::shared_ptr<Playlist> pl;
894 if (ranges.empty()) {
895 return boost::shared_ptr<Playlist>();
898 start = ranges.front().start;
900 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
902 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
904 if (i == ranges.begin()) {
908 /* paste the next section into the nascent playlist,
909 offset to reflect the start of the first range we
913 ret->paste (pl, (*i).start - start, 1.0f);
920 boost::shared_ptr<Playlist>
921 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
923 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
924 return cut_copy (pmf, ranges, result_is_hidden);
927 boost::shared_ptr<Playlist>
928 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
930 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
931 return cut_copy (pmf, ranges, result_is_hidden);
934 boost::shared_ptr<Playlist>
935 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
937 boost::shared_ptr<Playlist> the_copy;
941 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
942 string new_name = _name;
946 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
947 return boost::shared_ptr<Playlist>();
950 partition_internal (start, start+cnt-1, true, thawlist);
952 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
953 (*i)->thaw ("playlist cut");
959 boost::shared_ptr<Playlist>
960 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
964 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
965 string new_name = _name;
969 cnt = min (_get_maximum_extent() - start, cnt);
970 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
974 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
976 times = fabs (times);
977 nframes_t old_length;
980 RegionLock rl1 (this);
981 RegionLock rl2 (other.get());
983 old_length = _get_maximum_extent();
985 int itimes = (int) floor (times);
986 nframes_t pos = position;
987 nframes_t shift = other->_get_maximum_extent();
988 layer_t top_layer = regions.size();
991 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
992 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
994 /* put these new regions on top of all existing ones, but preserve
995 the ordering they had in the original playlist.
998 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
999 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1005 /* XXX shall we handle fractional cases at some point? */
1007 if (old_length != _get_maximum_extent()) {
1008 notify_length_changed ();
1019 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1021 times = fabs (times);
1023 RegionLock rl (this);
1024 int itimes = (int) floor (times);
1025 nframes_t pos = position;
1028 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1029 add_region_internal (copy, pos);
1030 pos += region->length();
1033 if (floor (times) != times) {
1034 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1036 _session.region_name (name, region->name(), false);
1037 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1038 add_region_internal (sub, pos);
1043 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1045 RegionLock rlock (this);
1046 RegionList copy (regions);
1049 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1051 if ((*r)->last_frame() < at) {
1056 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1057 /* intersected region */
1058 if (!move_intersected) {
1063 /* do not move regions glued to music time - that
1064 has to be done separately.
1067 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1068 fixup.push_back (*r);
1072 (*r)->set_position ((*r)->position() + distance, this);
1075 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1076 (*r)->recompute_position_from_lock_style ();
1081 Playlist::split (nframes64_t at)
1083 RegionLock rlock (this);
1084 RegionList copy (regions);
1086 /* use a copy since this operation can modify the region list
1089 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1090 _split_region (*r, at);
1095 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1097 RegionLock rl (this);
1098 _split_region (region, playlist_position);
1102 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1104 if (!region->covers (playlist_position)) {
1108 if (region->position() == playlist_position ||
1109 region->last_frame() == playlist_position) {
1113 boost::shared_ptr<Region> left;
1114 boost::shared_ptr<Region> right;
1120 /* split doesn't change anything about length, so don't try to splice */
1122 bool old_sp = _splicing;
1125 before = playlist_position - region->position();
1126 after = region->length() - before;
1128 _session.region_name (before_name, region->name(), false);
1129 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1131 _session.region_name (after_name, region->name(), false);
1132 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1134 add_region_internal (left, region->position());
1135 add_region_internal (right, region->position() + before);
1137 uint64_t orig_layer_op = region->last_layer_op();
1138 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1139 if ((*i)->last_layer_op() > orig_layer_op) {
1140 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1144 left->set_last_layer_op ( orig_layer_op );
1145 right->set_last_layer_op ( orig_layer_op + 1);
1149 finalize_split_region (region, left, right);
1151 remove_region_internal (region);
1157 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1159 if (_splicing || in_set_state) {
1160 /* don't respond to splicing moves or state setting */
1164 if (_edit_mode == Splice) {
1165 splice_locked (at, distance, exclude);
1170 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1172 if (_splicing || in_set_state) {
1173 /* don't respond to splicing moves or state setting */
1177 if (_edit_mode == Splice) {
1178 splice_unlocked (at, distance, exclude);
1183 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1186 RegionLock rl (this);
1187 core_splice (at, distance, exclude);
1192 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1194 core_splice (at, distance, exclude);
1198 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1202 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1204 if (exclude && (*i) == exclude) {
1208 if ((*i)->position() >= at) {
1209 nframes64_t new_pos = (*i)->position() + distance;
1212 } else if (new_pos >= max_frames - (*i)->length()) {
1213 new_pos = max_frames - (*i)->length();
1216 (*i)->set_position (new_pos, this);
1222 notify_length_changed ();
1226 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1228 if (in_set_state || _splicing || _nudging || _shuffling) {
1232 if (what_changed & ARDOUR::PositionChanged) {
1234 /* remove it from the list then add it back in
1235 the right place again.
1238 RegionSortByPosition cmp;
1240 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1242 if (i == regions.end()) {
1243 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1244 _name, region->name())
1250 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1253 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1255 nframes64_t delta = 0;
1257 if (what_changed & ARDOUR::PositionChanged) {
1258 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1261 if (what_changed & ARDOUR::LengthChanged) {
1262 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1266 possibly_splice (region->last_position() + region->last_length(), delta, region);
1269 if (holding_state ()) {
1270 pending_bounds.push_back (region);
1272 if (Config->get_layer_model() == MoveAddHigher) {
1273 /* it moved or changed length, so change the timestamp */
1274 timestamp_layer_op (region);
1277 notify_length_changed ();
1279 check_dependents (region, false);
1285 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1287 boost::shared_ptr<Region> region (weak_region.lock());
1294 /* this makes a virtual call to the right kind of playlist ... */
1296 region_changed (what_changed, region);
1300 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1302 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1305 if (in_set_state || in_flush) {
1309 if (what_changed & BoundsChanged) {
1310 region_bounds_changed (what_changed, region);
1311 save = !(_splicing || _nudging);
1314 if ((what_changed & our_interests) &&
1315 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1316 check_dependents (region, false);
1319 if (what_changed & Change (ARDOUR::PositionChanged)) {
1320 notify_region_moved (region);
1323 if (what_changed & our_interests) {
1331 Playlist::drop_regions ()
1333 RegionLock rl (this);
1335 all_regions.clear ();
1339 Playlist::clear (bool with_signals)
1342 RegionLock rl (this);
1345 std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
1346 i != region_state_changed_connections.end ();
1354 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1355 pending_removes.insert (*i);
1361 pending_length = false;
1363 pending_modified = false;
1369 /***********************************************************************
1371 **********************************************************************/
1373 Playlist::RegionList *
1374 Playlist::regions_at (nframes_t frame)
1377 RegionLock rlock (this);
1378 return find_regions_at (frame);
1381 boost::shared_ptr<Region>
1382 Playlist::top_region_at (nframes_t frame)
1385 RegionLock rlock (this);
1386 RegionList *rlist = find_regions_at (frame);
1387 boost::shared_ptr<Region> region;
1389 if (rlist->size()) {
1390 RegionSortByLayer cmp;
1392 region = rlist->back();
1399 Playlist::RegionList*
1400 Playlist::regions_to_read (nframes_t start, nframes_t end)
1402 /* Caller must hold lock */
1404 RegionList covering;
1405 set<nframes_t> to_check;
1406 set<boost::shared_ptr<Region> > unique;
1409 to_check.insert (start);
1410 to_check.insert (end);
1412 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1414 /* find all/any regions that span start+end */
1416 switch ((*i)->coverage (start, end)) {
1420 case OverlapInternal:
1421 covering.push_back (*i);
1425 to_check.insert ((*i)->position());
1426 covering.push_back (*i);
1430 to_check.insert ((*i)->last_frame());
1431 covering.push_back (*i);
1434 case OverlapExternal:
1435 covering.push_back (*i);
1436 to_check.insert ((*i)->position());
1437 to_check.insert ((*i)->last_frame());
1441 /* don't go too far */
1443 if ((*i)->position() > end) {
1448 RegionList* rlist = new RegionList;
1450 /* find all the regions that cover each position .... */
1452 if (covering.size() == 1) {
1454 rlist->push_back (covering.front());
1458 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1462 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1464 if ((*x)->covers (*t)) {
1465 here.push_back (*x);
1469 RegionSortByLayer cmp;
1472 /* ... and get the top/transparent regions at "here" */
1474 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1478 if ((*c)->opaque()) {
1480 /* the other regions at this position are hidden by this one */
1487 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1488 rlist->push_back (*s);
1491 if (rlist->size() > 1) {
1492 /* now sort by time order */
1494 RegionSortByPosition cmp;
1502 Playlist::RegionList *
1503 Playlist::find_regions_at (nframes_t frame)
1505 /* Caller must hold lock */
1507 RegionList *rlist = new RegionList;
1509 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1510 if ((*i)->covers (frame)) {
1511 rlist->push_back (*i);
1518 Playlist::RegionList *
1519 Playlist::regions_touched (nframes_t start, nframes_t end)
1521 RegionLock rlock (this);
1522 RegionList *rlist = new RegionList;
1524 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1525 if ((*i)->coverage (start, end) != OverlapNone) {
1526 rlist->push_back (*i);
1534 Playlist::find_next_transient (nframes64_t from, int dir)
1536 RegionLock rlock (this);
1537 AnalysisFeatureList points;
1538 AnalysisFeatureList these_points;
1540 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1542 if ((*i)->last_frame() < from) {
1546 if ((*i)->first_frame() > from) {
1551 (*i)->get_transients (these_points);
1553 /* add first frame, just, err, because */
1555 these_points.push_back ((*i)->first_frame());
1557 points.insert (points.end(), these_points.begin(), these_points.end());
1558 these_points.clear ();
1561 if (points.empty()) {
1565 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1566 bool reached = false;
1569 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1574 if (reached && (*x) > from) {
1579 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1584 if (reached && (*x) < from) {
1593 boost::shared_ptr<Region>
1594 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1596 RegionLock rlock (this);
1597 boost::shared_ptr<Region> ret;
1598 nframes_t closest = max_frames;
1600 bool end_iter = false;
1602 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1607 boost::shared_ptr<Region> r = (*i);
1612 pos = r->first_frame ();
1615 pos = r->last_frame ();
1618 pos = r->sync_position ();
1619 // r->adjust_to_sync (r->first_frame());
1624 case 1: /* forwards */
1627 if ((distance = pos - frame) < closest) {
1636 default: /* backwards */
1639 if ((distance = frame - pos) < closest) {
1656 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1658 RegionLock rlock (this);
1660 nframes64_t closest = max_frames;
1661 nframes64_t ret = -1;
1665 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1667 boost::shared_ptr<Region> r = (*i);
1668 nframes64_t distance;
1670 if (r->first_frame() > frame) {
1672 distance = r->first_frame() - frame;
1674 if (distance < closest) {
1675 ret = r->first_frame();
1680 if (r->last_frame () > frame) {
1682 distance = r->last_frame () - frame;
1684 if (distance < closest) {
1685 ret = r->last_frame ();
1693 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1695 boost::shared_ptr<Region> r = (*i);
1696 nframes64_t distance;
1698 if (r->last_frame() < frame) {
1700 distance = frame - r->last_frame();
1702 if (distance < closest) {
1703 ret = r->last_frame();
1708 if (r->first_frame() < frame) {
1710 distance = frame - r->first_frame();
1712 if (distance < closest) {
1713 ret = r->first_frame();
1723 /***********************************************************************/
1729 Playlist::mark_session_dirty ()
1731 if (!in_set_state && !holding_state ()) {
1732 _session.set_dirty();
1737 Playlist::set_state (const XMLNode& node)
1741 XMLNodeConstIterator niter;
1742 XMLPropertyList plist;
1743 XMLPropertyConstIterator piter;
1745 boost::shared_ptr<Region> region;
1750 if (node.name() != "Playlist") {
1757 plist = node.properties();
1759 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1763 if (prop->name() == X_("name")) {
1764 _name = prop->value();
1765 } else if (prop->name() == X_("orig_diskstream_id")) {
1766 _orig_diskstream_id = prop->value ();
1767 } else if (prop->name() == X_("frozen")) {
1768 _frozen = (prop->value() == X_("yes"));
1774 nlist = node.children();
1776 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1780 if (child->name() == "Region") {
1782 if ((prop = child->property ("id")) == 0) {
1783 error << _("region state node has no ID, ignored") << endmsg;
1787 ID id = prop->value ();
1789 if ((region = region_by_id (id))) {
1791 Change what_changed = Change (0);
1793 if (region->set_live_state (*child, what_changed, true)) {
1794 error << _("Playlist: cannot reset region state from XML") << endmsg;
1798 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1799 error << _("Playlist: cannot create region from XML") << endmsg;
1803 add_region (region, region->position(), 1.0);
1805 // So that layer_op ordering doesn't get screwed up
1806 region->set_last_layer_op( region->layer());
1815 /* update dependents, which was not done during add_region_internal
1816 due to in_set_state being true
1819 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1820 check_dependents (*r, false);
1824 first_set_state = false;
1829 Playlist::get_state()
1835 Playlist::get_template()
1837 return state(false);
1841 Playlist::state (bool full_state)
1843 XMLNode *node = new XMLNode (X_("Playlist"));
1846 node->add_property (X_("name"), _name);
1847 node->add_property (X_("type"), _type.to_string());
1849 _orig_diskstream_id.print (buf, sizeof (buf));
1850 node->add_property (X_("orig_diskstream_id"), buf);
1851 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1854 RegionLock rlock (this, false);
1855 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1856 node->add_child_nocopy ((*i)->get_state());
1861 node->add_child_copy (*_extra_xml);
1868 Playlist::empty() const
1870 RegionLock rlock (const_cast<Playlist *>(this), false);
1871 return regions.empty();
1875 Playlist::n_regions() const
1877 RegionLock rlock (const_cast<Playlist *>(this), false);
1878 return regions.size();
1882 Playlist::get_maximum_extent () const
1884 RegionLock rlock (const_cast<Playlist *>(this), false);
1885 return _get_maximum_extent ();
1889 Playlist::_get_maximum_extent () const
1891 RegionList::const_iterator i;
1892 nframes_t max_extent = 0;
1895 for (i = regions.begin(); i != regions.end(); ++i) {
1896 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1905 Playlist::bump_name (string name, Session &session)
1907 string newname = name;
1910 newname = bump_name_once (newname);
1911 } while (session.playlist_by_name (newname)!=NULL);
1918 Playlist::top_layer() const
1920 RegionLock rlock (const_cast<Playlist *> (this));
1923 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1924 top = max (top, (*i)->layer());
1930 Playlist::set_edit_mode (EditMode mode)
1935 /********************
1937 ********************/
1940 Playlist::relayer ()
1942 /* don't send multiple Modified notifications
1943 when multiple regions are relayered.
1948 /* build up a new list of regions on each layer */
1950 std::vector<RegionList> layers;
1952 /* we want to go through regions from desired lowest to desired highest layer,
1953 which depends on the layer model
1956 RegionList copy = regions;
1958 /* sort according to the model */
1960 if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
1961 RegionSortByLastLayerOp cmp;
1965 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1967 /* find the lowest layer that this region can go on */
1968 size_t j = layers.size();
1970 /* try layer j - 1; it can go on if it overlaps no other region
1971 that is already on that layer
1973 RegionList::iterator k = layers[j - 1].begin();
1974 while (k != layers[j - 1].end()) {
1975 if ((*k)->overlap_equivalent (*i)) {
1981 if (k != layers[j - 1].end()) {
1982 /* no overlap, so we can use this layer */
1989 if (j == layers.size()) {
1990 /* we need a new layer for this region */
1991 layers.push_back (RegionList ());
1994 layers[j].push_back (*i);
1997 /* first pass: set up the layer numbers in the regions */
1998 for (size_t j = 0; j < layers.size(); ++j) {
1999 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
2000 (*i)->set_layer (j);
2004 /* sending Modified means that various kinds of layering
2005 models operate correctly at the GUI
2006 level. slightly inefficient, but only slightly.
2008 We force a Modified signal here in case no layers actually
2017 /* XXX these layer functions are all deprecated */
2020 Playlist::raise_region (boost::shared_ptr<Region> region)
2022 uint32_t rsz = regions.size();
2023 layer_t target = region->layer() + 1U;
2025 if (target >= rsz) {
2026 /* its already at the effective top */
2030 move_region_to_layer (target, region, 1);
2034 Playlist::lower_region (boost::shared_ptr<Region> region)
2036 if (region->layer() == 0) {
2037 /* its already at the bottom */
2041 layer_t target = region->layer() - 1U;
2043 move_region_to_layer (target, region, -1);
2047 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2049 /* does nothing useful if layering mode is later=higher */
2050 if ((Config->get_layer_model() == MoveAddHigher) ||
2051 (Config->get_layer_model() == AddHigher)) {
2052 timestamp_layer_op (region);
2058 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2060 /* does nothing useful if layering mode is later=higher */
2061 if ((Config->get_layer_model() == MoveAddHigher) ||
2062 (Config->get_layer_model() == AddHigher)) {
2063 region->set_last_layer_op (0);
2069 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2071 RegionList::iterator i;
2072 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2073 list<LayerInfo> layerinfo;
2077 RegionLock rlock (const_cast<Playlist *> (this));
2079 for (i = regions.begin(); i != regions.end(); ++i) {
2087 /* region is moving up, move all regions on intermediate layers
2091 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2092 dest = (*i)->layer() - 1;
2099 /* region is moving down, move all regions on intermediate layers
2103 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2104 dest = (*i)->layer() + 1;
2114 newpair.second = dest;
2116 layerinfo.push_back (newpair);
2120 /* now reset the layers without holding the region lock */
2122 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2123 x->first->set_layer (x->second);
2126 region->set_layer (target_layer);
2129 /* now check all dependents */
2131 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2132 check_dependents (x->first, false);
2135 check_dependents (region, false);
2142 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2144 RegionList::iterator i;
2151 RegionLock rlock (const_cast<Playlist *> (this));
2153 for (i = regions.begin(); i != regions.end(); ++i) {
2155 if ((*i)->position() >= start) {
2159 if ((*i)->last_frame() > max_frames - distance) {
2160 new_pos = max_frames - (*i)->length();
2162 new_pos = (*i)->position() + distance;
2167 if ((*i)->position() > distance) {
2168 new_pos = (*i)->position() - distance;
2174 (*i)->set_position (new_pos, this);
2182 notify_length_changed ();
2187 boost::shared_ptr<Region>
2188 Playlist::find_region (const ID& id) const
2190 RegionLock rlock (const_cast<Playlist*> (this));
2192 /* searches all regions currently in use by the playlist */
2194 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2195 if ((*i)->id() == id) {
2200 return boost::shared_ptr<Region> ();
2203 boost::shared_ptr<Region>
2204 Playlist::region_by_id (ID id)
2206 /* searches all regions ever added to this playlist */
2208 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2209 if ((*i)->id() == id) {
2213 return boost::shared_ptr<Region> ();
2217 Playlist::dump () const
2219 boost::shared_ptr<Region> r;
2221 cerr << "Playlist \"" << _name << "\" " << endl
2222 << regions.size() << " regions "
2225 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2227 cerr << " " << r->name() << " ["
2228 << r->start() << "+" << r->length()
2238 Playlist::set_frozen (bool yn)
2244 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2246 // struct timeval tv;
2247 // gettimeofday (&tv, 0);
2248 region->set_last_layer_op (++layer_op_counter);
2253 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2258 if (region->locked()) {
2265 RegionLock rlock (const_cast<Playlist*> (this));
2270 RegionList::iterator next;
2272 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2273 if ((*i) == region) {
2277 if (next != regions.end()) {
2279 if ((*next)->locked()) {
2283 if ((*next)->position() != region->last_frame() + 1) {
2284 /* they didn't used to touch, so after shuffle,
2285 just have them swap positions.
2287 new_pos = (*next)->position();
2289 /* they used to touch, so after shuffle,
2290 make sure they still do. put the earlier
2291 region where the later one will end after
2294 new_pos = region->position() + (*next)->length();
2297 (*next)->set_position (region->position(), this);
2298 region->set_position (new_pos, this);
2300 /* avoid a full sort */
2302 regions.erase (i); // removes the region from the list */
2304 regions.insert (next, region); // adds it back after next
2313 RegionList::iterator prev = regions.end();
2315 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2316 if ((*i) == region) {
2318 if (prev != regions.end()) {
2320 if ((*prev)->locked()) {
2324 if (region->position() != (*prev)->last_frame() + 1) {
2325 /* they didn't used to touch, so after shuffle,
2326 just have them swap positions.
2328 new_pos = region->position();
2330 /* they used to touch, so after shuffle,
2331 make sure they still do. put the earlier
2332 one where the later one will end after
2334 new_pos = (*prev)->position() + region->length();
2337 region->set_position ((*prev)->position(), this);
2338 (*prev)->set_position (new_pos, this);
2340 /* avoid a full sort */
2342 regions.erase (i); // remove region
2343 regions.insert (prev, region); // insert region before prev
2359 check_dependents (region, false);
2367 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2369 RegionLock rlock (const_cast<Playlist*> (this));
2371 if (regions.size() > 1) {
2379 Playlist::update_after_tempo_map_change ()
2381 RegionLock rlock (const_cast<Playlist*> (this));
2382 RegionList copy (regions);
2386 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2387 (*i)->update_position_after_tempo_map_change ();