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 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
346 Modified (); /* EMIT SIGNAL */
351 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
353 Evoral::RangeMove<nframes_t> const move (r->last_position (), r->length (), r->position ());
355 if (holding_state ()) {
357 pending_range_moves.push_back (move);
361 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 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
384 Modified (); /* EMIT SIGNAL */
389 Playlist::notify_length_changed ()
391 if (holding_state ()) {
392 pending_length = true;
394 pending_length = false;
395 LengthChanged(); /* EMIT SIGNAL */
396 pending_modified = false;
397 Modified (); /* EMIT SIGNAL */
402 Playlist::flush_notifications ()
404 set<boost::shared_ptr<Region> > dependent_checks_needed;
405 set<boost::shared_ptr<Region> >::iterator s;
414 /* we have no idea what order the regions ended up in pending
415 bounds (it could be based on selection order, for example).
416 so, to preserve layering in the "most recently moved is higher"
417 model, sort them by existing layer, then timestamp them.
420 // RegionSortByLayer cmp;
421 // pending_bounds.sort (cmp);
423 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
424 if (_session.config.get_layer_model() == MoveAddHigher) {
425 timestamp_layer_op (*r);
428 pending_length = true;
429 dependent_checks_needed.insert (*r);
434 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
435 remove_dependents (*s);
436 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
440 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
441 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
442 dependent_checks_needed.insert (*s);
446 if ((freeze_length != _get_maximum_extent()) || pending_length) {
448 LengthChanged(); /* EMIT SIGNAL */
452 if (n || pending_modified) {
456 pending_modified = false;
457 Modified (); /* EMIT SIGNAL */
460 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
461 check_dependents (*s, false);
464 if (!pending_range_moves.empty ()) {
465 RangesMoved (pending_range_moves);
468 pending_adds.clear ();
469 pending_removes.clear ();
470 pending_bounds.clear ();
471 pending_range_moves.clear ();
476 /*************************************************************
478 *************************************************************/
481 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times, bool auto_partition)
483 RegionLock rlock (this);
484 times = fabs (times);
486 int itimes = (int) floor (times);
488 nframes_t pos = position;
490 if(times == 1 && auto_partition){
491 partition(pos, (nframes_t) (pos + region->length()), true);
495 add_region_internal (region, pos);
496 pos += region->length();
501 /* note that itimes can be zero if we being asked to just
502 insert a single fraction of the region.
505 for (int i = 0; i < itimes; ++i) {
506 boost::shared_ptr<Region> copy = RegionFactory::create (region);
507 add_region_internal (copy, pos);
508 pos += region->length();
511 nframes_t length = 0;
513 if (floor (times) != times) {
514 length = (nframes_t) floor (region->length() * (times - floor (times)));
516 _session.region_name (name, region->name(), false);
517 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
518 add_region_internal (sub, pos);
521 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
525 Playlist::set_region_ownership ()
527 RegionLock rl (this);
528 RegionList::iterator i;
529 boost::weak_ptr<Playlist> pl (shared_from_this());
531 for (i = regions.begin(); i != regions.end(); ++i) {
532 (*i)->set_playlist (pl);
537 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
539 if (region->data_type() != _type){
543 RegionSortByPosition cmp;
545 nframes_t old_length = 0;
547 if (!holding_state()) {
548 old_length = _get_maximum_extent();
551 if (!first_set_state) {
552 boost::shared_ptr<Playlist> foo (shared_from_this());
553 region->set_playlist (boost::weak_ptr<Playlist>(foo));
556 region->set_position (position, this);
558 timestamp_layer_op (region);
560 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
561 all_regions.insert (region);
563 possibly_splice_unlocked (position, region->length(), region);
565 if (!holding_state () && !in_set_state) {
566 /* layers get assigned from XML state */
570 /* we need to notify the existence of new region before checking dependents. Ick. */
572 notify_region_added (region);
574 if (!holding_state ()) {
576 check_dependents (region, false);
578 if (old_length != _get_maximum_extent()) {
579 notify_length_changed ();
583 region_state_changed_connections.push_back (
584 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
585 boost::weak_ptr<Region> (region)))
592 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
594 RegionLock rlock (this);
596 bool old_sp = _splicing;
599 remove_region_internal (old);
600 add_region_internal (newr, pos);
604 possibly_splice_unlocked (pos, (nframes64_t) old->length() - (nframes64_t) newr->length());
608 Playlist::remove_region (boost::shared_ptr<Region> region)
610 RegionLock rlock (this);
611 remove_region_internal (region);
615 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
617 RegionList::iterator i;
618 nframes_t old_length = 0;
620 if (!holding_state()) {
621 old_length = _get_maximum_extent();
626 region->set_playlist (boost::weak_ptr<Playlist>());
629 for (i = regions.begin(); i != regions.end(); ++i) {
632 nframes_t pos = (*i)->position();
633 nframes64_t distance = (*i)->length();
637 possibly_splice_unlocked (pos, -distance);
639 if (!holding_state ()) {
641 remove_dependents (region);
643 if (old_length != _get_maximum_extent()) {
644 notify_length_changed ();
648 notify_region_removed (region);
659 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
661 if (Config->get_use_overlap_equivalency()) {
662 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
663 if ((*i)->overlap_equivalent (other)) {
664 results.push_back ((*i));
668 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
669 if ((*i)->equivalent (other)) {
670 results.push_back ((*i));
677 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
679 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
681 if ((*i) && (*i)->region_list_equivalent (other)) {
682 results.push_back (*i);
688 Playlist::partition (nframes_t start, nframes_t end, bool cut)
692 partition_internal (start, end, cut, thawlist);
694 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
695 (*i)->thaw ("separation");
700 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
702 RegionList new_regions;
705 RegionLock rlock (this);
707 boost::shared_ptr<Region> region;
708 boost::shared_ptr<Region> current;
710 RegionList::iterator tmp;
712 nframes_t pos1, pos2, pos3, pos4;
716 /* need to work from a copy, because otherwise the regions we add during the process
717 get operated on as well.
720 RegionList copy = regions;
722 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
729 if (current->first_frame() >= start && current->last_frame() < end) {
732 remove_region_internal (current);
738 /* coverage will return OverlapStart if the start coincides
739 with the end point. we do not partition such a region,
740 so catch this special case.
743 if (current->first_frame() >= end) {
747 if ((overlap = current->coverage (start, end)) == OverlapNone) {
751 pos1 = current->position();
754 pos4 = current->last_frame();
756 if (overlap == OverlapInternal) {
757 /* split: we need 3 new regions, the front, middle and end.
758 cut: we need 2 regions, the front and end.
763 ---------------*************************------------
766 ---------------*****++++++++++++++++====------------
768 ---------------*****----------------====------------
773 /* "middle" ++++++ */
775 _session.region_name (new_name, current->name(), false);
776 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
777 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
778 add_region_internal (region, start);
779 new_regions.push_back (region);
784 _session.region_name (new_name, current->name(), false);
785 region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
786 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
788 add_region_internal (region, end);
789 new_regions.push_back (region);
794 thawlist.push_back (current);
795 current->trim_end (pos2, this);
797 } else if (overlap == OverlapEnd) {
801 ---------------*************************------------
804 ---------------**************+++++++++++------------
806 ---------------**************-----------------------
813 _session.region_name (new_name, current->name(), false);
814 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
815 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
817 add_region_internal (region, start);
818 new_regions.push_back (region);
824 thawlist.push_back (current);
825 current->trim_end (pos2, this);
827 } else if (overlap == OverlapStart) {
829 /* split: we need 2 regions: the front and the end.
830 cut: just trim current to skip the cut area
835 ---------------*************************------------
839 ---------------****+++++++++++++++++++++------------
841 -------------------*********************------------
847 _session.region_name (new_name, current->name(), false);
848 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
849 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
851 add_region_internal (region, pos1);
852 new_regions.push_back (region);
858 thawlist.push_back (current);
859 current->trim_front (pos3, this);
860 } else if (overlap == OverlapExternal) {
862 /* split: no split required.
863 cut: remove the region.
868 ---------------*************************------------
872 ---------------*************************------------
874 ----------------------------------------------------
879 remove_region_internal (current);
882 new_regions.push_back (current);
886 in_partition = false;
889 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
890 check_dependents (*i, false);
894 boost::shared_ptr<Playlist>
895 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
897 boost::shared_ptr<Playlist> ret;
898 boost::shared_ptr<Playlist> pl;
901 if (ranges.empty()) {
902 return boost::shared_ptr<Playlist>();
905 start = ranges.front().start;
907 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
909 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
911 if (i == ranges.begin()) {
915 /* paste the next section into the nascent playlist,
916 offset to reflect the start of the first range we
920 ret->paste (pl, (*i).start - start, 1.0f);
927 boost::shared_ptr<Playlist>
928 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
930 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
931 return cut_copy (pmf, ranges, result_is_hidden);
934 boost::shared_ptr<Playlist>
935 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
937 boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
938 return cut_copy (pmf, ranges, result_is_hidden);
941 boost::shared_ptr<Playlist>
942 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
944 boost::shared_ptr<Playlist> the_copy;
948 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
949 string new_name = _name;
953 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
954 return boost::shared_ptr<Playlist>();
957 partition_internal (start, start+cnt-1, true, thawlist);
959 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
960 (*i)->thaw ("playlist cut");
966 boost::shared_ptr<Playlist>
967 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
971 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
972 string new_name = _name;
976 cnt = min (_get_maximum_extent() - start, cnt);
977 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
981 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
983 times = fabs (times);
984 nframes_t old_length;
987 RegionLock rl1 (this);
988 RegionLock rl2 (other.get());
990 old_length = _get_maximum_extent();
992 int itimes = (int) floor (times);
993 nframes_t pos = position;
994 nframes_t shift = other->_get_maximum_extent();
995 layer_t top_layer = regions.size();
998 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
999 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1001 /* put these new regions on top of all existing ones, but preserve
1002 the ordering they had in the original playlist.
1005 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1006 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1012 /* XXX shall we handle fractional cases at some point? */
1014 if (old_length != _get_maximum_extent()) {
1015 notify_length_changed ();
1026 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
1028 times = fabs (times);
1030 RegionLock rl (this);
1031 int itimes = (int) floor (times);
1032 nframes_t pos = position;
1035 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1036 add_region_internal (copy, pos);
1037 pos += region->length();
1040 if (floor (times) != times) {
1041 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
1043 _session.region_name (name, region->name(), false);
1044 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
1045 add_region_internal (sub, pos);
1050 Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue)
1052 RegionLock rlock (this);
1053 RegionList copy (regions);
1056 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1058 if ((*r)->last_frame() < at) {
1063 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1064 /* intersected region */
1065 if (!move_intersected) {
1070 /* do not move regions glued to music time - that
1071 has to be done separately.
1074 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1075 fixup.push_back (*r);
1079 (*r)->set_position ((*r)->position() + distance, this);
1082 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1083 (*r)->recompute_position_from_lock_style ();
1088 Playlist::split (nframes64_t at)
1090 RegionLock rlock (this);
1091 RegionList copy (regions);
1093 /* use a copy since this operation can modify the region list
1096 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1097 _split_region (*r, at);
1102 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1104 RegionLock rl (this);
1105 _split_region (region, playlist_position);
1109 Playlist::_split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
1111 if (!region->covers (playlist_position)) {
1115 if (region->position() == playlist_position ||
1116 region->last_frame() == playlist_position) {
1120 boost::shared_ptr<Region> left;
1121 boost::shared_ptr<Region> right;
1127 /* split doesn't change anything about length, so don't try to splice */
1129 bool old_sp = _splicing;
1132 before = playlist_position - region->position();
1133 after = region->length() - before;
1135 _session.region_name (before_name, region->name(), false);
1136 left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1138 _session.region_name (after_name, region->name(), false);
1139 right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1141 add_region_internal (left, region->position());
1142 add_region_internal (right, region->position() + before);
1144 uint64_t orig_layer_op = region->last_layer_op();
1145 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1146 if ((*i)->last_layer_op() > orig_layer_op) {
1147 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1151 left->set_last_layer_op ( orig_layer_op );
1152 right->set_last_layer_op ( orig_layer_op + 1);
1156 finalize_split_region (region, left, right);
1158 remove_region_internal (region);
1164 Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1166 if (_splicing || in_set_state) {
1167 /* don't respond to splicing moves or state setting */
1171 if (_edit_mode == Splice) {
1172 splice_locked (at, distance, exclude);
1177 Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1179 if (_splicing || in_set_state) {
1180 /* don't respond to splicing moves or state setting */
1184 if (_edit_mode == Splice) {
1185 splice_unlocked (at, distance, exclude);
1190 Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1193 RegionLock rl (this);
1194 core_splice (at, distance, exclude);
1199 Playlist::splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1201 core_splice (at, distance, exclude);
1205 Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude)
1209 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1211 if (exclude && (*i) == exclude) {
1215 if ((*i)->position() >= at) {
1216 nframes64_t new_pos = (*i)->position() + distance;
1219 } else if (new_pos >= max_frames - (*i)->length()) {
1220 new_pos = max_frames - (*i)->length();
1223 (*i)->set_position (new_pos, this);
1229 notify_length_changed ();
1233 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1235 if (in_set_state || _splicing || _nudging || _shuffling) {
1239 if (what_changed & ARDOUR::PositionChanged) {
1241 /* remove it from the list then add it back in
1242 the right place again.
1245 RegionSortByPosition cmp;
1247 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1249 if (i == regions.end()) {
1250 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1251 _name, region->name())
1257 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1260 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1262 nframes64_t delta = 0;
1264 if (what_changed & ARDOUR::PositionChanged) {
1265 delta = (nframes64_t) region->position() - (nframes64_t) region->last_position();
1268 if (what_changed & ARDOUR::LengthChanged) {
1269 delta += (nframes64_t) region->length() - (nframes64_t) region->last_length();
1273 possibly_splice (region->last_position() + region->last_length(), delta, region);
1276 if (holding_state ()) {
1277 pending_bounds.push_back (region);
1279 if (_session.config.get_layer_model() == MoveAddHigher) {
1280 /* it moved or changed length, so change the timestamp */
1281 timestamp_layer_op (region);
1284 notify_length_changed ();
1286 check_dependents (region, false);
1292 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1294 boost::shared_ptr<Region> region (weak_region.lock());
1301 /* this makes a virtual call to the right kind of playlist ... */
1303 region_changed (what_changed, region);
1307 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1309 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1312 if (in_set_state || in_flush) {
1316 if (what_changed & BoundsChanged) {
1317 region_bounds_changed (what_changed, region);
1318 save = !(_splicing || _nudging);
1321 if ((what_changed & our_interests) &&
1322 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1323 check_dependents (region, false);
1326 if (what_changed & Change (ARDOUR::PositionChanged)) {
1327 notify_region_moved (region);
1330 if (what_changed & our_interests) {
1338 Playlist::drop_regions ()
1340 RegionLock rl (this);
1342 all_regions.clear ();
1346 Playlist::clear (bool with_signals)
1349 RegionLock rl (this);
1352 std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
1353 i != region_state_changed_connections.end ();
1359 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1360 pending_removes.insert (*i);
1367 pending_length = false;
1369 pending_modified = false;
1375 /***********************************************************************
1377 **********************************************************************/
1379 Playlist::RegionList *
1380 Playlist::regions_at (nframes_t frame)
1383 RegionLock rlock (this);
1384 return find_regions_at (frame);
1387 boost::shared_ptr<Region>
1388 Playlist::top_region_at (nframes_t frame)
1391 RegionLock rlock (this);
1392 RegionList *rlist = find_regions_at (frame);
1393 boost::shared_ptr<Region> region;
1395 if (rlist->size()) {
1396 RegionSortByLayer cmp;
1398 region = rlist->back();
1405 Playlist::RegionList*
1406 Playlist::regions_to_read (nframes_t start, nframes_t end)
1408 /* Caller must hold lock */
1410 RegionList covering;
1411 set<nframes_t> to_check;
1412 set<boost::shared_ptr<Region> > unique;
1415 to_check.insert (start);
1416 to_check.insert (end);
1418 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1420 /* find all/any regions that span start+end */
1422 switch ((*i)->coverage (start, end)) {
1426 case OverlapInternal:
1427 covering.push_back (*i);
1431 to_check.insert ((*i)->position());
1432 covering.push_back (*i);
1436 to_check.insert ((*i)->last_frame());
1437 covering.push_back (*i);
1440 case OverlapExternal:
1441 covering.push_back (*i);
1442 to_check.insert ((*i)->position());
1443 to_check.insert ((*i)->last_frame());
1447 /* don't go too far */
1449 if ((*i)->position() > end) {
1454 RegionList* rlist = new RegionList;
1456 /* find all the regions that cover each position .... */
1458 if (covering.size() == 1) {
1460 rlist->push_back (covering.front());
1464 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1468 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1470 if ((*x)->covers (*t)) {
1471 here.push_back (*x);
1475 RegionSortByLayer cmp;
1478 /* ... and get the top/transparent regions at "here" */
1480 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1484 if ((*c)->opaque()) {
1486 /* the other regions at this position are hidden by this one */
1493 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1494 rlist->push_back (*s);
1497 if (rlist->size() > 1) {
1498 /* now sort by time order */
1500 RegionSortByPosition cmp;
1508 Playlist::RegionList *
1509 Playlist::find_regions_at (nframes_t frame)
1511 /* Caller must hold lock */
1513 RegionList *rlist = new RegionList;
1515 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1516 if ((*i)->covers (frame)) {
1517 rlist->push_back (*i);
1524 Playlist::RegionList *
1525 Playlist::regions_touched (nframes_t start, nframes_t end)
1527 RegionLock rlock (this);
1528 RegionList *rlist = new RegionList;
1530 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1531 if ((*i)->coverage (start, end) != OverlapNone) {
1532 rlist->push_back (*i);
1540 Playlist::find_next_transient (nframes64_t from, int dir)
1542 RegionLock rlock (this);
1543 AnalysisFeatureList points;
1544 AnalysisFeatureList these_points;
1546 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1548 if ((*i)->last_frame() < from) {
1552 if ((*i)->first_frame() > from) {
1557 (*i)->get_transients (these_points);
1559 /* add first frame, just, err, because */
1561 these_points.push_back ((*i)->first_frame());
1563 points.insert (points.end(), these_points.begin(), these_points.end());
1564 these_points.clear ();
1567 if (points.empty()) {
1571 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1572 bool reached = false;
1575 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1580 if (reached && (*x) > from) {
1585 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1590 if (reached && (*x) < from) {
1599 boost::shared_ptr<Region>
1600 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1602 RegionLock rlock (this);
1603 boost::shared_ptr<Region> ret;
1604 nframes_t closest = max_frames;
1606 bool end_iter = false;
1608 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1613 boost::shared_ptr<Region> r = (*i);
1618 pos = r->first_frame ();
1621 pos = r->last_frame ();
1624 pos = r->sync_position ();
1625 // r->adjust_to_sync (r->first_frame());
1630 case 1: /* forwards */
1633 if ((distance = pos - frame) < closest) {
1642 default: /* backwards */
1645 if ((distance = frame - pos) < closest) {
1662 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1664 RegionLock rlock (this);
1666 nframes64_t closest = max_frames;
1667 nframes64_t ret = -1;
1671 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1673 boost::shared_ptr<Region> r = (*i);
1674 nframes64_t distance;
1676 if (r->first_frame() > frame) {
1678 distance = r->first_frame() - frame;
1680 if (distance < closest) {
1681 ret = r->first_frame();
1686 if (r->last_frame () > frame) {
1688 distance = r->last_frame () - frame;
1690 if (distance < closest) {
1691 ret = r->last_frame ();
1699 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1701 boost::shared_ptr<Region> r = (*i);
1702 nframes64_t distance;
1704 if (r->last_frame() < frame) {
1706 distance = frame - r->last_frame();
1708 if (distance < closest) {
1709 ret = r->last_frame();
1714 if (r->first_frame() < frame) {
1716 distance = frame - r->first_frame();
1718 if (distance < closest) {
1719 ret = r->first_frame();
1729 /***********************************************************************/
1735 Playlist::mark_session_dirty ()
1737 if (!in_set_state && !holding_state ()) {
1738 _session.set_dirty();
1743 Playlist::set_state (const XMLNode& node)
1747 XMLNodeConstIterator niter;
1748 XMLPropertyList plist;
1749 XMLPropertyConstIterator piter;
1751 boost::shared_ptr<Region> region;
1756 if (node.name() != "Playlist") {
1763 plist = node.properties();
1765 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1769 if (prop->name() == X_("name")) {
1770 _name = prop->value();
1771 } else if (prop->name() == X_("orig_diskstream_id")) {
1772 _orig_diskstream_id = prop->value ();
1773 } else if (prop->name() == X_("frozen")) {
1774 _frozen = (prop->value() == X_("yes"));
1780 nlist = node.children();
1782 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1786 if (child->name() == "Region") {
1788 if ((prop = child->property ("id")) == 0) {
1789 error << _("region state node has no ID, ignored") << endmsg;
1793 ID id = prop->value ();
1795 if ((region = region_by_id (id))) {
1797 Change what_changed = Change (0);
1799 if (region->set_live_state (*child, what_changed, true)) {
1800 error << _("Playlist: cannot reset region state from XML") << endmsg;
1804 } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1805 error << _("Playlist: cannot create region from XML") << endmsg;
1809 add_region (region, region->position(), 1.0);
1811 // So that layer_op ordering doesn't get screwed up
1812 region->set_last_layer_op( region->layer());
1821 /* update dependents, which was not done during add_region_internal
1822 due to in_set_state being true
1825 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1826 check_dependents (*r, false);
1830 first_set_state = false;
1835 Playlist::get_state()
1841 Playlist::get_template()
1843 return state(false);
1847 Playlist::state (bool full_state)
1849 XMLNode *node = new XMLNode (X_("Playlist"));
1852 node->add_property (X_("name"), _name);
1853 node->add_property (X_("type"), _type.to_string());
1855 _orig_diskstream_id.print (buf, sizeof (buf));
1856 node->add_property (X_("orig_diskstream_id"), buf);
1857 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1860 RegionLock rlock (this, false);
1861 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1862 node->add_child_nocopy ((*i)->get_state());
1867 node->add_child_copy (*_extra_xml);
1874 Playlist::empty() const
1876 RegionLock rlock (const_cast<Playlist *>(this), false);
1877 return regions.empty();
1881 Playlist::n_regions() const
1883 RegionLock rlock (const_cast<Playlist *>(this), false);
1884 return regions.size();
1888 Playlist::get_maximum_extent () const
1890 RegionLock rlock (const_cast<Playlist *>(this), false);
1891 return _get_maximum_extent ();
1895 Playlist::_get_maximum_extent () const
1897 RegionList::const_iterator i;
1898 nframes_t max_extent = 0;
1901 for (i = regions.begin(); i != regions.end(); ++i) {
1902 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1911 Playlist::bump_name (string name, Session &session)
1913 string newname = name;
1916 newname = bump_name_once (newname);
1917 } while (session.playlist_by_name (newname)!=NULL);
1924 Playlist::top_layer() const
1926 RegionLock rlock (const_cast<Playlist *> (this));
1929 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1930 top = max (top, (*i)->layer());
1936 Playlist::set_edit_mode (EditMode mode)
1941 /********************
1943 ********************/
1946 Playlist::relayer ()
1948 /* don't send multiple Modified notifications
1949 when multiple regions are relayered.
1954 /* build up a new list of regions on each layer */
1956 std::vector<RegionList> layers;
1958 /* we want to go through regions from desired lowest to desired highest layer,
1959 which depends on the layer model
1962 RegionList copy = regions;
1964 /* sort according to the model */
1966 if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
1967 RegionSortByLastLayerOp cmp;
1971 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1973 /* find the lowest layer that this region can go on */
1974 size_t j = layers.size();
1976 /* try layer j - 1; it can go on if it overlaps no other region
1977 that is already on that layer
1979 RegionList::iterator k = layers[j - 1].begin();
1980 while (k != layers[j - 1].end()) {
1981 if ((*k)->overlap_equivalent (*i)) {
1987 if (k != layers[j - 1].end()) {
1988 /* no overlap, so we can use this layer */
1995 if (j == layers.size()) {
1996 /* we need a new layer for this region */
1997 layers.push_back (RegionList ());
2000 layers[j].push_back (*i);
2003 /* first pass: set up the layer numbers in the regions */
2004 for (size_t j = 0; j < layers.size(); ++j) {
2005 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
2006 (*i)->set_layer (j);
2010 /* sending Modified means that various kinds of layering
2011 models operate correctly at the GUI
2012 level. slightly inefficient, but only slightly.
2014 We force a Modified signal here in case no layers actually
2023 /* XXX these layer functions are all deprecated */
2026 Playlist::raise_region (boost::shared_ptr<Region> region)
2028 uint32_t rsz = regions.size();
2029 layer_t target = region->layer() + 1U;
2031 if (target >= rsz) {
2032 /* its already at the effective top */
2036 move_region_to_layer (target, region, 1);
2040 Playlist::lower_region (boost::shared_ptr<Region> region)
2042 if (region->layer() == 0) {
2043 /* its already at the bottom */
2047 layer_t target = region->layer() - 1U;
2049 move_region_to_layer (target, region, -1);
2053 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2055 /* does nothing useful if layering mode is later=higher */
2056 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2057 (_session.config.get_layer_model() == AddHigher)) {
2058 timestamp_layer_op (region);
2064 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2066 /* does nothing useful if layering mode is later=higher */
2067 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2068 (_session.config.get_layer_model() == AddHigher)) {
2069 region->set_last_layer_op (0);
2075 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2077 RegionList::iterator i;
2078 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2079 list<LayerInfo> layerinfo;
2083 RegionLock rlock (const_cast<Playlist *> (this));
2085 for (i = regions.begin(); i != regions.end(); ++i) {
2093 /* region is moving up, move all regions on intermediate layers
2097 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2098 dest = (*i)->layer() - 1;
2105 /* region is moving down, move all regions on intermediate layers
2109 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2110 dest = (*i)->layer() + 1;
2120 newpair.second = dest;
2122 layerinfo.push_back (newpair);
2126 /* now reset the layers without holding the region lock */
2128 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2129 x->first->set_layer (x->second);
2132 region->set_layer (target_layer);
2135 /* now check all dependents */
2137 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2138 check_dependents (x->first, false);
2141 check_dependents (region, false);
2148 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2150 RegionList::iterator i;
2157 RegionLock rlock (const_cast<Playlist *> (this));
2159 for (i = regions.begin(); i != regions.end(); ++i) {
2161 if ((*i)->position() >= start) {
2165 if ((*i)->last_frame() > max_frames - distance) {
2166 new_pos = max_frames - (*i)->length();
2168 new_pos = (*i)->position() + distance;
2173 if ((*i)->position() > distance) {
2174 new_pos = (*i)->position() - distance;
2180 (*i)->set_position (new_pos, this);
2188 notify_length_changed ();
2193 boost::shared_ptr<Region>
2194 Playlist::find_region (const ID& id) const
2196 RegionLock rlock (const_cast<Playlist*> (this));
2198 /* searches all regions currently in use by the playlist */
2200 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2201 if ((*i)->id() == id) {
2206 return boost::shared_ptr<Region> ();
2209 boost::shared_ptr<Region>
2210 Playlist::region_by_id (ID id)
2212 /* searches all regions ever added to this playlist */
2214 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2215 if ((*i)->id() == id) {
2219 return boost::shared_ptr<Region> ();
2223 Playlist::dump () const
2225 boost::shared_ptr<Region> r;
2227 cerr << "Playlist \"" << _name << "\" " << endl
2228 << regions.size() << " regions "
2231 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2233 cerr << " " << r->name() << " ["
2234 << r->start() << "+" << r->length()
2244 Playlist::set_frozen (bool yn)
2250 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2252 // struct timeval tv;
2253 // gettimeofday (&tv, 0);
2254 region->set_last_layer_op (++layer_op_counter);
2259 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2264 if (region->locked()) {
2271 RegionLock rlock (const_cast<Playlist*> (this));
2276 RegionList::iterator next;
2278 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2279 if ((*i) == region) {
2283 if (next != regions.end()) {
2285 if ((*next)->locked()) {
2289 if ((*next)->position() != region->last_frame() + 1) {
2290 /* they didn't used to touch, so after shuffle,
2291 just have them swap positions.
2293 new_pos = (*next)->position();
2295 /* they used to touch, so after shuffle,
2296 make sure they still do. put the earlier
2297 region where the later one will end after
2300 new_pos = region->position() + (*next)->length();
2303 (*next)->set_position (region->position(), this);
2304 region->set_position (new_pos, this);
2306 /* avoid a full sort */
2308 regions.erase (i); // removes the region from the list */
2310 regions.insert (next, region); // adds it back after next
2319 RegionList::iterator prev = regions.end();
2321 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2322 if ((*i) == region) {
2324 if (prev != regions.end()) {
2326 if ((*prev)->locked()) {
2330 if (region->position() != (*prev)->last_frame() + 1) {
2331 /* they didn't used to touch, so after shuffle,
2332 just have them swap positions.
2334 new_pos = region->position();
2336 /* they used to touch, so after shuffle,
2337 make sure they still do. put the earlier
2338 one where the later one will end after
2340 new_pos = (*prev)->position() + region->length();
2343 region->set_position ((*prev)->position(), this);
2344 (*prev)->set_position (new_pos, this);
2346 /* avoid a full sort */
2348 regions.erase (i); // remove region
2349 regions.insert (prev, region); // insert region before prev
2365 check_dependents (region, false);
2373 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2375 RegionLock rlock (const_cast<Playlist*> (this));
2377 if (regions.size() > 1) {
2385 Playlist::update_after_tempo_map_change ()
2387 RegionLock rlock (const_cast<Playlist*> (this));
2388 RegionList copy (regions);
2392 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2393 (*i)->update_position_after_tempo_map_change ();
2400 Playlist::foreach_region (sigc::slot<void, boost::shared_ptr<Region> > s)
2402 RegionLock rl (this, false);
2403 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {