2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <boost/lexical_cast.hpp>
31 #include "pbd/failed_constructor.h"
32 #include "pbd/stateful_diff_command.h"
33 #include "pbd/xml++.h"
34 #include "pbd/stacktrace.h"
36 #include "ardour/debug.h"
37 #include "ardour/playlist.h"
38 #include "ardour/session.h"
39 #include "ardour/region.h"
40 #include "ardour/region_factory.h"
41 #include "ardour/playlist_factory.h"
42 #include "ardour/transient_detector.h"
43 #include "ardour/session_playlists.h"
48 using namespace ARDOUR;
52 namespace Properties {
53 PBD::PropertyDescriptor<bool> regions;
57 struct ShowMeTheList {
58 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
60 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
62 boost::shared_ptr<Playlist> playlist;
66 struct RegionSortByLayer {
67 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
68 return a->layer() < b->layer();
72 struct RegionSortByLayerWithPending {
73 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
75 double p = a->layer ();
76 if (a->pending_explicit_relayer()) {
80 double q = b->layer ();
81 if (b->pending_explicit_relayer()) {
89 struct RegionSortByPosition {
90 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
91 return a->position() < b->position();
95 struct RegionSortByLastLayerOp {
96 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
97 return a->last_layer_op() < b->last_layer_op();
102 Playlist::make_property_quarks ()
104 Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
105 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n", Properties::regions.property_id));
108 RegionListProperty::RegionListProperty (Playlist& pl)
109 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
115 RegionListProperty::RegionListProperty (RegionListProperty const & p)
116 : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
117 , _playlist (p._playlist)
123 RegionListProperty::clone () const
125 return new RegionListProperty (*this);
129 RegionListProperty::create () const
131 return new RegionListProperty (_playlist);
135 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
137 /* All regions (even those which are deleted) have their state saved by other
138 code, so we can just store ID here.
141 node.add_property ("id", region->id().to_s ());
144 boost::shared_ptr<Region>
145 RegionListProperty::get_content_from_xml (XMLNode const & node) const
147 XMLProperty const * prop = node.property ("id");
150 PBD::ID id (prop->value ());
152 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
155 ret = RegionFactory::region_by_id (id);
161 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
162 : SessionObject(sess, nom)
167 first_set_state = false;
173 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
174 : SessionObject(sess, "unnamed playlist")
180 const XMLProperty* prop = node.property("type");
181 assert(!prop || DataType(prop->value()) == _type);
185 _name = "unnamed"; /* reset by set_state */
188 /* set state called by derived class */
191 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
192 : SessionObject(other->_session, namestr)
194 , _type(other->_type)
195 , _orig_diskstream_id (other->_orig_diskstream_id)
200 other->copy_regions (tmp);
204 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
205 add_region_internal( (*x), (*x)->position());
210 _splicing = other->_splicing;
211 _nudging = other->_nudging;
212 _edit_mode = other->_edit_mode;
215 first_set_state = false;
217 in_partition = false;
219 _read_data_count = 0;
220 _frozen = other->_frozen;
222 layer_op_counter = other->layer_op_counter;
223 freeze_length = other->freeze_length;
226 Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
227 : SessionObject(other->_session, str)
229 , _type(other->_type)
230 , _orig_diskstream_id (other->_orig_diskstream_id)
232 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
234 framepos_t end = start + cnt - 1;
240 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
242 boost::shared_ptr<Region> region;
243 boost::shared_ptr<Region> new_region;
244 frameoffset_t offset = 0;
245 framepos_t position = 0;
252 overlap = region->coverage (start, end);
258 case OverlapInternal:
259 offset = start - region->position();
266 position = region->position() - start;
267 len = end - region->position();
271 offset = start - region->position();
273 len = region->length() - offset;
276 case OverlapExternal:
278 position = region->position() - start;
279 len = region->length();
283 RegionFactory::region_name (new_name, region->name(), false);
287 plist.add (Properties::start, region->start() + offset);
288 plist.add (Properties::length, len);
289 plist.add (Properties::name, new_name);
290 plist.add (Properties::layer, region->layer());
292 new_region = RegionFactory::RegionFactory::create (region, plist);
294 add_region_internal (new_region, position);
298 first_set_state = false;
300 /* this constructor does NOT notify others (session) */
307 InUse (true); /* EMIT SIGNAL */
318 InUse (false); /* EMIT SIGNAL */
323 Playlist::copy_regions (RegionList& newlist) const
325 RegionLock rlock (const_cast<Playlist *> (this));
327 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
328 newlist.push_back (RegionFactory::RegionFactory::create (*i, true));
333 Playlist::init (bool hide)
335 add_property (regions);
336 _xml_node_name = X_("Playlist");
338 g_atomic_int_set (&block_notifications, 0);
339 g_atomic_int_set (&ignore_state_changes, 0);
340 pending_contents_change = false;
341 pending_length = false;
342 pending_layering = false;
343 first_set_state = true;
351 _edit_mode = Config->get_edit_mode();
353 in_partition = false;
355 _read_data_count = 0;
357 layer_op_counter = 0;
359 _explicit_relayering = false;
361 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
362 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
364 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
367 Playlist::~Playlist ()
369 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
372 RegionLock rl (this);
374 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
375 (*i)->set_playlist (boost::shared_ptr<Playlist>());
379 /* GoingAway must be emitted by derived classes */
383 Playlist::_set_sort_id ()
386 Playlists are given names like <track name>.<id>
387 or <track name>.<edit group name>.<id> where id
388 is an integer. We extract the id and sort by that.
391 size_t dot_position = _name.val().find_last_of(".");
393 if (dot_position == string::npos) {
396 string t = _name.val().substr(dot_position + 1);
399 _sort_id = boost::lexical_cast<int>(t);
402 catch (boost::bad_lexical_cast e) {
409 Playlist::set_name (const string& str)
411 /* in a typical situation, a playlist is being used
412 by one diskstream and also is referenced by the
413 Session. if there are more references than that,
414 then don't change the name.
421 bool ret = SessionObject::set_name(str);
428 /***********************************************************************
429 CHANGE NOTIFICATION HANDLING
431 Notifications must be delayed till the region_lock is released. This
432 is necessary because handlers for the signals may need to acquire
433 the lock (e.g. to read from the playlist).
434 ***********************************************************************/
437 Playlist::begin_undo ()
444 Playlist::end_undo ()
453 delay_notifications ();
454 g_atomic_int_inc (&ignore_state_changes);
457 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
459 Playlist::thaw (bool from_undo)
461 g_atomic_int_dec_and_test (&ignore_state_changes);
462 release_notifications (from_undo);
467 Playlist::delay_notifications ()
469 g_atomic_int_inc (&block_notifications);
470 freeze_length = _get_extent().second;
473 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
475 Playlist::release_notifications (bool from_undo)
477 if (g_atomic_int_dec_and_test (&block_notifications)) {
478 flush_notifications (from_undo);
484 Playlist::notify_contents_changed ()
486 if (holding_state ()) {
487 pending_contents_change = true;
489 pending_contents_change = false;
490 ContentsChanged(); /* EMIT SIGNAL */
495 Playlist::notify_layering_changed ()
497 if (holding_state ()) {
498 pending_layering = true;
500 pending_layering = false;
501 LayeringChanged(); /* EMIT SIGNAL */
506 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
508 if (holding_state ()) {
509 pending_removes.insert (r);
510 pending_contents_change = true;
511 pending_length = true;
513 /* this might not be true, but we have to act
514 as though it could be.
516 pending_length = false;
517 LengthChanged (); /* EMIT SIGNAL */
518 pending_contents_change = false;
519 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
520 ContentsChanged (); /* EMIT SIGNAL */
525 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
527 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
529 if (holding_state ()) {
531 pending_range_moves.push_back (move);
535 list< Evoral::RangeMove<framepos_t> > m;
537 RangesMoved (m, false);
543 Playlist::notify_region_added (boost::shared_ptr<Region> r)
545 /* the length change might not be true, but we have to act
546 as though it could be.
549 if (holding_state()) {
550 pending_adds.insert (r);
551 pending_contents_change = true;
552 pending_length = true;
555 pending_length = false;
556 LengthChanged (); /* EMIT SIGNAL */
557 pending_contents_change = false;
558 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
559 ContentsChanged (); /* EMIT SIGNAL */
564 Playlist::notify_length_changed ()
566 if (holding_state ()) {
567 pending_length = true;
569 pending_length = false;
570 LengthChanged(); /* EMIT SIGNAL */
571 pending_contents_change = false;
572 ContentsChanged (); /* EMIT SIGNAL */
576 /** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
578 Playlist::flush_notifications (bool from_undo)
580 set<boost::shared_ptr<Region> > dependent_checks_needed;
581 set<boost::shared_ptr<Region> >::iterator s;
582 uint32_t regions_changed = false;
583 bool check_length = false;
584 framecnt_t old_length = 0;
592 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
593 regions_changed = true;
594 if (!pending_length) {
595 old_length = _get_extent ().second;
600 /* we have no idea what order the regions ended up in pending
601 bounds (it could be based on selection order, for example).
602 so, to preserve layering in the "most recently moved is higher"
603 model, sort them by existing layer, then timestamp them.
606 // RegionSortByLayer cmp;
607 // pending_bounds.sort (cmp);
609 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
610 if (_session.config.get_layer_model() == MoveAddHigher) {
611 timestamp_layer_op (*r);
613 dependent_checks_needed.insert (*r);
616 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
617 remove_dependents (*s);
618 // cerr << _name << " sends RegionRemoved\n";
619 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
622 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
623 // cerr << _name << " sends RegionAdded\n";
624 /* don't emit RegionAdded signal until relayering is done,
625 so that the region is fully setup by the time
626 anyone hear's that its been added
628 dependent_checks_needed.insert (*s);
632 if (old_length != _get_extent().second) {
633 pending_length = true;
634 // cerr << _name << " length has changed\n";
638 if (pending_length || (freeze_length != _get_extent().second)) {
639 pending_length = false;
640 // cerr << _name << " sends LengthChanged\n";
641 LengthChanged(); /* EMIT SIGNAL */
644 if (regions_changed || pending_contents_change) {
648 pending_contents_change = false;
649 // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
650 ContentsChanged (); /* EMIT SIGNAL */
651 // cerr << _name << "done contents change @ " << get_microseconds() << endl;
654 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
655 (*s)->clear_changes ();
656 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
659 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
660 check_dependents (*s, false);
663 if (!pending_range_moves.empty ()) {
664 RangesMoved (pending_range_moves, from_undo);
673 Playlist::clear_pending ()
675 pending_adds.clear ();
676 pending_removes.clear ();
677 pending_bounds.clear ();
678 pending_range_moves.clear ();
679 pending_contents_change = false;
680 pending_length = false;
683 /*************************************************************
685 *************************************************************/
688 Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
690 RegionLock rlock (this);
691 times = fabs (times);
693 int itimes = (int) floor (times);
695 framepos_t pos = position;
697 if (times == 1 && auto_partition){
698 partition(pos - 1, (pos + region->length()), true);
702 add_region_internal (region, pos);
703 pos += region->length();
708 /* note that itimes can be zero if we being asked to just
709 insert a single fraction of the region.
712 for (int i = 0; i < itimes; ++i) {
713 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
714 add_region_internal (copy, pos);
715 pos += region->length();
718 framecnt_t length = 0;
720 if (floor (times) != times) {
721 length = (framecnt_t) floor (region->length() * (times - floor (times)));
723 RegionFactory::region_name (name, region->name(), false);
728 plist.add (Properties::start, region->start());
729 plist.add (Properties::length, length);
730 plist.add (Properties::name, name);
731 plist.add (Properties::layer, region->layer());
733 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
734 add_region_internal (sub, pos);
738 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
742 Playlist::set_region_ownership ()
744 RegionLock rl (this);
745 RegionList::iterator i;
746 boost::weak_ptr<Playlist> pl (shared_from_this());
748 for (i = regions.begin(); i != regions.end(); ++i) {
749 (*i)->set_playlist (pl);
754 Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
756 if (region->data_type() != _type){
760 RegionSortByPosition cmp;
762 framecnt_t old_length = 0;
764 if (!holding_state()) {
765 old_length = _get_extent().second;
768 if (!first_set_state) {
769 boost::shared_ptr<Playlist> foo (shared_from_this());
770 region->set_playlist (boost::weak_ptr<Playlist>(foo));
773 region->set_position (position, this);
775 timestamp_layer_op (region);
777 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
778 all_regions.insert (region);
780 possibly_splice_unlocked (position, region->length(), region);
782 if (!holding_state ()) {
783 /* layers get assigned from XML state, and are not reset during undo/redo */
787 /* we need to notify the existence of new region before checking dependents. Ick. */
789 notify_region_added (region);
791 if (!holding_state ()) {
793 check_dependents (region, false);
795 if (old_length != _get_extent().second) {
796 notify_length_changed ();
800 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
806 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
808 RegionLock rlock (this);
810 bool old_sp = _splicing;
813 remove_region_internal (old);
814 add_region_internal (newr, pos);
818 possibly_splice_unlocked (pos, old->length() - newr->length());
822 Playlist::remove_region (boost::shared_ptr<Region> region)
824 RegionLock rlock (this);
825 remove_region_internal (region);
829 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
831 RegionList::iterator i;
832 framecnt_t old_length = 0;
835 if (!holding_state()) {
836 old_length = _get_extent().second;
841 region->set_playlist (boost::weak_ptr<Playlist>());
844 /* XXX should probably freeze here .... */
846 for (i = regions.begin(); i != regions.end(); ++i) {
849 framepos_t pos = (*i)->position();
850 framecnt_t distance = (*i)->length();
854 possibly_splice_unlocked (pos, -distance);
856 if (!holding_state ()) {
858 remove_dependents (region);
860 if (old_length != _get_extent().second) {
861 notify_length_changed ();
865 notify_region_removed (region);
875 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
877 if (Config->get_use_overlap_equivalency()) {
878 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
879 if ((*i)->overlap_equivalent (other)) {
880 results.push_back ((*i));
884 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
885 if ((*i)->equivalent (other)) {
886 results.push_back ((*i));
893 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
895 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
897 if ((*i) && (*i)->region_list_equivalent (other)) {
898 results.push_back (*i);
904 Playlist::partition (framepos_t start, framepos_t end, bool cut)
908 partition_internal (start, end, cut, thawlist);
910 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
911 (*i)->resume_property_changes ();
916 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
918 RegionList new_regions;
921 RegionLock rlock (this);
923 boost::shared_ptr<Region> region;
924 boost::shared_ptr<Region> current;
926 RegionList::iterator tmp;
928 framepos_t pos1, pos2, pos3, pos4;
932 /* need to work from a copy, because otherwise the regions we add during the process
933 get operated on as well.
936 RegionList copy = regions.rlist();
938 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
945 if (current->first_frame() >= start && current->last_frame() < end) {
948 remove_region_internal (current);
954 /* coverage will return OverlapStart if the start coincides
955 with the end point. we do not partition such a region,
956 so catch this special case.
959 if (current->first_frame() >= end) {
963 if ((overlap = current->coverage (start, end)) == OverlapNone) {
967 pos1 = current->position();
970 pos4 = current->last_frame();
972 if (overlap == OverlapInternal) {
973 /* split: we need 3 new regions, the front, middle and end.
974 cut: we need 2 regions, the front and end.
979 ---------------*************************------------
982 ---------------*****++++++++++++++++====------------
984 ---------------*****----------------====------------
989 /* "middle" ++++++ */
991 RegionFactory::region_name (new_name, current->name(), false);
995 plist.add (Properties::start, current->start() + (pos2 - pos1));
996 plist.add (Properties::length, pos3 - pos2);
997 plist.add (Properties::name, new_name);
998 plist.add (Properties::layer, regions.size());
999 plist.add (Properties::automatic, true);
1000 plist.add (Properties::left_of_split, true);
1001 plist.add (Properties::right_of_split, true);
1003 region = RegionFactory::create (current, plist);
1004 add_region_internal (region, start);
1005 new_regions.push_back (region);
1010 RegionFactory::region_name (new_name, current->name(), false);
1014 plist.add (Properties::start, current->start() + (pos3 - pos1));
1015 plist.add (Properties::length, pos4 - pos3);
1016 plist.add (Properties::name, new_name);
1017 plist.add (Properties::layer, regions.size());
1018 plist.add (Properties::automatic, true);
1019 plist.add (Properties::right_of_split, true);
1021 region = RegionFactory::create (current, plist);
1023 add_region_internal (region, end);
1024 new_regions.push_back (region);
1028 current->suspend_property_changes ();
1029 thawlist.push_back (current);
1030 current->cut_end (pos2 - 1, this);
1032 } else if (overlap == OverlapEnd) {
1036 ---------------*************************------------
1039 ---------------**************+++++++++++------------
1041 ---------------**************-----------------------
1048 RegionFactory::region_name (new_name, current->name(), false);
1052 plist.add (Properties::start, current->start() + (pos2 - pos1));
1053 plist.add (Properties::length, pos4 - pos2);
1054 plist.add (Properties::name, new_name);
1055 plist.add (Properties::layer, regions.size());
1056 plist.add (Properties::automatic, true);
1057 plist.add (Properties::left_of_split, true);
1059 region = RegionFactory::create (current, plist);
1061 add_region_internal (region, start);
1062 new_regions.push_back (region);
1067 current->suspend_property_changes ();
1068 thawlist.push_back (current);
1069 current->cut_end (pos2 - 1, this);
1071 } else if (overlap == OverlapStart) {
1073 /* split: we need 2 regions: the front and the end.
1074 cut: just trim current to skip the cut area
1079 ---------------*************************------------
1083 ---------------****+++++++++++++++++++++------------
1085 -------------------*********************------------
1091 RegionFactory::region_name (new_name, current->name(), false);
1095 plist.add (Properties::start, current->start());
1096 plist.add (Properties::length, pos3 - pos1);
1097 plist.add (Properties::name, new_name);
1098 plist.add (Properties::layer, regions.size());
1099 plist.add (Properties::automatic, true);
1100 plist.add (Properties::right_of_split, true);
1102 region = RegionFactory::create (current, plist);
1104 add_region_internal (region, pos1);
1105 new_regions.push_back (region);
1110 current->suspend_property_changes ();
1111 thawlist.push_back (current);
1112 current->trim_front (pos3, this);
1113 } else if (overlap == OverlapExternal) {
1115 /* split: no split required.
1116 cut: remove the region.
1121 ---------------*************************------------
1125 ---------------*************************------------
1127 ----------------------------------------------------
1132 remove_region_internal (current);
1135 new_regions.push_back (current);
1139 in_partition = false;
1142 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1143 check_dependents (*i, false);
1147 boost::shared_ptr<Playlist>
1148 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1150 boost::shared_ptr<Playlist> ret;
1151 boost::shared_ptr<Playlist> pl;
1154 if (ranges.empty()) {
1155 return boost::shared_ptr<Playlist>();
1158 start = ranges.front().start;
1160 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1162 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1164 if (i == ranges.begin()) {
1168 /* paste the next section into the nascent playlist,
1169 offset to reflect the start of the first range we
1173 ret->paste (pl, (*i).start - start, 1.0f);
1180 boost::shared_ptr<Playlist>
1181 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1183 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1184 return cut_copy (pmf, ranges, result_is_hidden);
1187 boost::shared_ptr<Playlist>
1188 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1190 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1191 return cut_copy (pmf, ranges, result_is_hidden);
1194 boost::shared_ptr<Playlist>
1195 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1197 boost::shared_ptr<Playlist> the_copy;
1198 RegionList thawlist;
1201 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1202 string new_name = _name;
1206 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1207 return boost::shared_ptr<Playlist>();
1210 partition_internal (start, start+cnt-1, true, thawlist);
1212 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1213 (*i)->resume_property_changes();
1219 boost::shared_ptr<Playlist>
1220 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1224 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1225 string new_name = _name;
1229 cnt = min (_get_extent().second - start, cnt);
1230 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1234 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1236 times = fabs (times);
1239 RegionLock rl1 (this);
1240 RegionLock rl2 (other.get());
1242 framecnt_t const old_length = _get_extent().second;
1244 int itimes = (int) floor (times);
1245 framepos_t pos = position;
1246 framecnt_t const shift = other->_get_extent().second;
1247 layer_t top_layer = regions.size();
1250 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1251 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1253 /* put these new regions on top of all existing ones, but preserve
1254 the ordering they had in the original playlist.
1257 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1258 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1264 /* XXX shall we handle fractional cases at some point? */
1266 if (old_length != _get_extent().second) {
1267 notify_length_changed ();
1278 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1280 times = fabs (times);
1282 RegionLock rl (this);
1283 int itimes = (int) floor (times);
1284 framepos_t pos = position + 1;
1287 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1288 add_region_internal (copy, pos);
1289 pos += region->length();
1292 if (floor (times) != times) {
1293 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1295 RegionFactory::region_name (name, region->name(), false);
1300 plist.add (Properties::start, region->start());
1301 plist.add (Properties::length, length);
1302 plist.add (Properties::name, name);
1304 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1305 add_region_internal (sub, pos);
1311 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1313 RegionLock rlock (this);
1314 RegionList copy (regions.rlist());
1317 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1319 if ((*r)->last_frame() < at) {
1324 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1325 /* intersected region */
1326 if (!move_intersected) {
1331 /* do not move regions glued to music time - that
1332 has to be done separately.
1335 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1336 fixup.push_back (*r);
1340 (*r)->set_position ((*r)->position() + distance, this);
1343 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1344 (*r)->recompute_position_from_lock_style ();
1349 Playlist::split (framepos_t at)
1351 RegionLock rlock (this);
1352 RegionList copy (regions.rlist());
1354 /* use a copy since this operation can modify the region list
1357 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1358 _split_region (*r, at);
1363 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1365 RegionLock rl (this);
1366 _split_region (region, playlist_position);
1370 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1372 if (!region->covers (playlist_position)) {
1376 if (region->position() == playlist_position ||
1377 region->last_frame() == playlist_position) {
1381 boost::shared_ptr<Region> left;
1382 boost::shared_ptr<Region> right;
1383 frameoffset_t before;
1384 frameoffset_t after;
1388 /* split doesn't change anything about length, so don't try to splice */
1390 bool old_sp = _splicing;
1393 before = playlist_position - region->position();
1394 after = region->length() - before;
1396 RegionFactory::region_name (before_name, region->name(), false);
1401 plist.add (Properties::length, before);
1402 plist.add (Properties::name, before_name);
1403 plist.add (Properties::left_of_split, true);
1405 /* note: we must use the version of ::create with an offset here,
1406 since it supplies that offset to the Region constructor, which
1407 is necessary to get audio region gain envelopes right.
1409 left = RegionFactory::create (region, 0, plist);
1412 RegionFactory::region_name (after_name, region->name(), false);
1417 plist.add (Properties::length, after);
1418 plist.add (Properties::name, after_name);
1419 plist.add (Properties::right_of_split, true);
1421 /* same note as above */
1422 right = RegionFactory::create (region, before, plist);
1425 add_region_internal (left, region->position());
1426 add_region_internal (right, region->position() + before);
1428 uint64_t orig_layer_op = region->last_layer_op();
1429 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1430 if ((*i)->last_layer_op() > orig_layer_op) {
1431 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1435 left->set_last_layer_op ( orig_layer_op );
1436 right->set_last_layer_op ( orig_layer_op + 1);
1440 finalize_split_region (region, left, right);
1442 remove_region_internal (region);
1448 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1450 if (_splicing || in_set_state) {
1451 /* don't respond to splicing moves or state setting */
1455 if (_edit_mode == Splice) {
1456 splice_locked (at, distance, exclude);
1461 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1463 if (_splicing || in_set_state) {
1464 /* don't respond to splicing moves or state setting */
1468 if (_edit_mode == Splice) {
1469 splice_unlocked (at, distance, exclude);
1474 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1477 RegionLock rl (this);
1478 core_splice (at, distance, exclude);
1483 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1485 core_splice (at, distance, exclude);
1489 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1493 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1495 if (exclude && (*i) == exclude) {
1499 if ((*i)->position() >= at) {
1500 framepos_t new_pos = (*i)->position() + distance;
1503 } else if (new_pos >= max_framepos - (*i)->length()) {
1504 new_pos = max_framepos - (*i)->length();
1507 (*i)->set_position (new_pos, this);
1513 notify_length_changed ();
1517 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1519 if (in_set_state || _splicing || _nudging || _shuffling) {
1523 if (what_changed.contains (Properties::position)) {
1525 /* remove it from the list then add it back in
1526 the right place again.
1529 RegionSortByPosition cmp;
1531 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1533 if (i == regions.end()) {
1534 /* the region bounds are being modified but its not currently
1535 in the region list. we will use its bounds correctly when/if
1542 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1545 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1547 frameoffset_t delta = 0;
1549 if (what_changed.contains (Properties::position)) {
1550 delta = region->position() - region->last_position();
1553 if (what_changed.contains (Properties::length)) {
1554 delta += region->length() - region->last_length();
1558 possibly_splice (region->last_position() + region->last_length(), delta, region);
1561 if (holding_state ()) {
1562 pending_bounds.push_back (region);
1564 if (_session.config.get_layer_model() == MoveAddHigher) {
1565 /* it moved or changed length, so change the timestamp */
1566 timestamp_layer_op (region);
1569 notify_length_changed ();
1571 check_dependents (region, false);
1577 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1579 boost::shared_ptr<Region> region (weak_region.lock());
1585 /* this makes a virtual call to the right kind of playlist ... */
1587 region_changed (what_changed, region);
1591 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1593 PropertyChange our_interests;
1594 PropertyChange bounds;
1595 PropertyChange pos_and_length;
1598 if (in_set_state || in_flush) {
1602 our_interests.add (Properties::muted);
1603 our_interests.add (Properties::layer);
1604 our_interests.add (Properties::opaque);
1606 bounds.add (Properties::start);
1607 bounds.add (Properties::position);
1608 bounds.add (Properties::length);
1610 pos_and_length.add (Properties::position);
1611 pos_and_length.add (Properties::length);
1613 if (what_changed.contains (bounds)) {
1614 region_bounds_changed (what_changed, region);
1615 save = !(_splicing || _nudging);
1618 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1619 check_dependents (region, false);
1622 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1623 notify_region_moved (region);
1627 /* don't notify about layer changes, since we are the only object that can initiate
1628 them, and we notify in ::relayer()
1631 if (what_changed.contains (our_interests)) {
1639 Playlist::drop_regions ()
1641 RegionLock rl (this);
1643 all_regions.clear ();
1647 Playlist::clear (bool with_signals)
1650 RegionLock rl (this);
1652 region_state_changed_connections.drop_connections ();
1654 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1655 pending_removes.insert (*i);
1660 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1661 remove_dependents (*s);
1667 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1668 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1671 pending_removes.clear ();
1672 pending_length = false;
1674 pending_contents_change = false;
1680 /***********************************************************************
1682 **********************************************************************/
1684 Playlist::RegionList *
1685 Playlist::regions_at (framepos_t frame)
1688 RegionLock rlock (this);
1689 return find_regions_at (frame);
1693 Playlist::count_regions_at (framepos_t frame)
1695 RegionLock rlock (this);
1698 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1699 if ((*i)->covers (frame)) {
1707 boost::shared_ptr<Region>
1708 Playlist::top_region_at (framepos_t frame)
1711 RegionLock rlock (this);
1712 RegionList *rlist = find_regions_at (frame);
1713 boost::shared_ptr<Region> region;
1715 if (rlist->size()) {
1716 RegionSortByLayer cmp;
1718 region = rlist->back();
1725 boost::shared_ptr<Region>
1726 Playlist::top_unmuted_region_at (framepos_t frame)
1729 RegionLock rlock (this);
1730 RegionList *rlist = find_regions_at (frame);
1732 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1734 RegionList::iterator tmp = i;
1737 if ((*i)->muted()) {
1744 boost::shared_ptr<Region> region;
1746 if (rlist->size()) {
1747 RegionSortByLayer cmp;
1749 region = rlist->back();
1756 Playlist::RegionList*
1757 Playlist::regions_to_read (framepos_t start, framepos_t end)
1759 /* Caller must hold lock */
1761 RegionList covering;
1762 set<framepos_t> to_check;
1763 set<boost::shared_ptr<Region> > unique;
1765 to_check.insert (start);
1766 to_check.insert (end);
1768 DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1770 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1772 /* find all/any regions that span start+end */
1774 switch ((*i)->coverage (start, end)) {
1778 case OverlapInternal:
1779 covering.push_back (*i);
1780 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1784 to_check.insert ((*i)->position());
1785 if ((*i)->position() != 0) {
1786 to_check.insert ((*i)->position()-1);
1788 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1789 covering.push_back (*i);
1793 to_check.insert ((*i)->last_frame());
1794 to_check.insert ((*i)->last_frame()+1);
1795 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1796 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1797 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1798 covering.push_back (*i);
1801 case OverlapExternal:
1802 covering.push_back (*i);
1803 to_check.insert ((*i)->position());
1804 if ((*i)->position() != 0) {
1805 to_check.insert ((*i)->position()-1);
1807 to_check.insert ((*i)->last_frame());
1808 to_check.insert ((*i)->last_frame()+1);
1809 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1810 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1811 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1815 /* don't go too far */
1817 if ((*i)->position() > end) {
1822 RegionList* rlist = new RegionList;
1824 /* find all the regions that cover each position .... */
1826 if (covering.size() == 1) {
1828 rlist->push_back (covering.front());
1829 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1834 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1838 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1840 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1842 if ((*x)->covers (*t)) {
1843 here.push_back (*x);
1844 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1848 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1855 RegionSortByLayer cmp;
1858 /* ... and get the top/transparent regions at "here" */
1860 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1864 if ((*c)->opaque()) {
1866 /* the other regions at this position are hidden by this one */
1867 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1874 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1875 rlist->push_back (*s);
1878 if (rlist->size() > 1) {
1879 /* now sort by time order */
1881 RegionSortByPosition cmp;
1886 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1891 Playlist::RegionList *
1892 Playlist::find_regions_at (framepos_t frame)
1894 /* Caller must hold lock */
1896 RegionList *rlist = new RegionList;
1898 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1899 if ((*i)->covers (frame)) {
1900 rlist->push_back (*i);
1907 Playlist::RegionList *
1908 Playlist::regions_touched (framepos_t start, framepos_t end)
1910 RegionLock rlock (this);
1911 RegionList *rlist = new RegionList;
1913 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1914 if ((*i)->coverage (start, end) != OverlapNone) {
1915 rlist->push_back (*i);
1923 Playlist::find_next_transient (framepos_t from, int dir)
1925 RegionLock rlock (this);
1926 AnalysisFeatureList points;
1927 AnalysisFeatureList these_points;
1929 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1931 if ((*i)->last_frame() < from) {
1935 if ((*i)->first_frame() > from) {
1940 (*i)->get_transients (these_points);
1942 /* add first frame, just, err, because */
1944 these_points.push_back ((*i)->first_frame());
1946 points.insert (points.end(), these_points.begin(), these_points.end());
1947 these_points.clear ();
1950 if (points.empty()) {
1954 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1955 bool reached = false;
1958 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1963 if (reached && (*x) > from) {
1968 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1973 if (reached && (*x) < from) {
1982 boost::shared_ptr<Region>
1983 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1985 RegionLock rlock (this);
1986 boost::shared_ptr<Region> ret;
1987 framepos_t closest = max_framepos;
1989 bool end_iter = false;
1991 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1995 frameoffset_t distance;
1996 boost::shared_ptr<Region> r = (*i);
2001 pos = r->first_frame ();
2004 pos = r->last_frame ();
2007 pos = r->sync_position ();
2012 case 1: /* forwards */
2015 if ((distance = pos - frame) < closest) {
2024 default: /* backwards */
2027 if ((distance = frame - pos) < closest) {
2044 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2046 RegionLock rlock (this);
2048 framepos_t closest = max_framepos;
2049 framepos_t ret = -1;
2053 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2055 boost::shared_ptr<Region> r = (*i);
2056 frameoffset_t distance;
2058 if (r->first_frame() > frame) {
2060 distance = r->first_frame() - frame;
2062 if (distance < closest) {
2063 ret = r->first_frame();
2068 if (r->last_frame () > frame) {
2070 distance = r->last_frame () - frame;
2072 if (distance < closest) {
2073 ret = r->last_frame ();
2081 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2083 boost::shared_ptr<Region> r = (*i);
2084 frameoffset_t distance;
2086 if (r->last_frame() < frame) {
2088 distance = frame - r->last_frame();
2090 if (distance < closest) {
2091 ret = r->last_frame();
2096 if (r->first_frame() < frame) {
2098 distance = frame - r->first_frame();
2100 if (distance < closest) {
2101 ret = r->first_frame();
2112 /***********************************************************************/
2118 Playlist::mark_session_dirty ()
2120 if (!in_set_state && !holding_state ()) {
2121 _session.set_dirty();
2126 Playlist::rdiff (vector<Command*>& cmds) const
2128 RegionLock rlock (const_cast<Playlist *> (this));
2129 Stateful::rdiff (cmds);
2133 Playlist::clear_owned_changes ()
2135 RegionLock rlock (this);
2136 Stateful::clear_owned_changes ();
2140 Playlist::update (const RegionListProperty::ChangeRecord& change)
2142 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2143 name(), change.added.size(), change.removed.size()));
2146 /* add the added regions */
2147 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2148 add_region ((*i), (*i)->position());
2150 /* remove the removed regions */
2151 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2159 Playlist::set_state (const XMLNode& node, int version)
2163 XMLNodeConstIterator niter;
2164 XMLPropertyList plist;
2165 XMLPropertyConstIterator piter;
2167 boost::shared_ptr<Region> region;
2172 if (node.name() != "Playlist") {
2179 plist = node.properties();
2181 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2185 if (prop->name() == X_("name")) {
2186 _name = prop->value();
2188 } else if (prop->name() == X_("id")) {
2189 _id = prop->value();
2190 } else if (prop->name() == X_("orig_diskstream_id")) {
2191 _orig_diskstream_id = prop->value ();
2192 } else if (prop->name() == X_("frozen")) {
2193 _frozen = string_is_affirmative (prop->value());
2199 nlist = node.children();
2201 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2205 if (child->name() == "Region") {
2207 if ((prop = child->property ("id")) == 0) {
2208 error << _("region state node has no ID, ignored") << endmsg;
2212 ID id = prop->value ();
2214 if ((region = region_by_id (id))) {
2216 region->suspend_property_changes ();
2218 if (region->set_state (*child, version)) {
2219 region->resume_property_changes ();
2223 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2224 region->suspend_property_changes ();
2226 error << _("Playlist: cannot create region from XML") << endmsg;
2231 add_region (region, region->position(), 1.0);
2233 // So that layer_op ordering doesn't get screwed up
2234 region->set_last_layer_op( region->layer());
2235 region->resume_property_changes ();
2239 /* update dependents, which was not done during add_region_internal
2240 due to in_set_state being true
2243 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2244 check_dependents (*r, false);
2248 notify_contents_changed ();
2251 first_set_state = false;
2256 Playlist::get_state()
2258 return state (true);
2262 Playlist::get_template()
2264 return state (false);
2267 /** @param full_state true to include regions in the returned state, otherwise false.
2270 Playlist::state (bool full_state)
2272 XMLNode *node = new XMLNode (X_("Playlist"));
2275 node->add_property (X_("id"), id().to_s());
2276 node->add_property (X_("name"), _name);
2277 node->add_property (X_("type"), _type.to_string());
2279 _orig_diskstream_id.print (buf, sizeof (buf));
2280 node->add_property (X_("orig_diskstream_id"), buf);
2281 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2284 RegionLock rlock (this, false);
2286 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2287 node->add_child_nocopy ((*i)->get_state());
2292 node->add_child_copy (*_extra_xml);
2299 Playlist::empty() const
2301 RegionLock rlock (const_cast<Playlist *>(this), false);
2302 return regions.empty();
2306 Playlist::n_regions() const
2308 RegionLock rlock (const_cast<Playlist *>(this), false);
2309 return regions.size();
2312 pair<framepos_t, framepos_t>
2313 Playlist::get_extent () const
2315 RegionLock rlock (const_cast<Playlist *>(this), false);
2316 return _get_extent ();
2319 pair<framepos_t, framepos_t>
2320 Playlist::_get_extent () const
2322 pair<framepos_t, framepos_t> ext (max_framepos, 0);
2324 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2325 pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2326 if (e.first < ext.first) {
2327 ext.first = e.first;
2329 if (e.second > ext.second) {
2330 ext.second = e.second;
2338 Playlist::bump_name (string name, Session &session)
2340 string newname = name;
2343 newname = bump_name_once (newname, '.');
2344 } while (session.playlists->by_name (newname)!=NULL);
2351 Playlist::top_layer() const
2353 RegionLock rlock (const_cast<Playlist *> (this));
2356 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2357 top = max (top, (*i)->layer());
2363 Playlist::set_edit_mode (EditMode mode)
2368 /********************
2370 ********************/
2373 Playlist::relayer ()
2375 /* never compute layers when changing state for undo/redo or setting from XML */
2377 if (in_update || in_set_state) {
2381 bool changed = false;
2383 /* Build up a new list of regions on each layer, stored in a set of lists
2384 each of which represent some period of time on some layer. The idea
2385 is to avoid having to search the entire region list to establish whether
2386 each region overlaps another */
2388 /* how many pieces to divide this playlist's time up into */
2389 int const divisions = 512;
2391 /* find the start and end positions of the regions on this playlist */
2392 framepos_t start = INT64_MAX;
2394 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2395 start = min (start, (*i)->position());
2396 end = max (end, (*i)->position() + (*i)->length());
2399 /* hence the size of each time division */
2400 double const division_size = (end - start) / double (divisions);
2402 vector<vector<RegionList> > layers;
2403 layers.push_back (vector<RegionList> (divisions));
2405 /* we want to go through regions from desired lowest to desired highest layer,
2406 which depends on the layer model
2409 RegionList copy = regions.rlist();
2411 /* sort according to the model and the layering mode that we're in */
2413 if (_explicit_relayering) {
2415 copy.sort (RegionSortByLayerWithPending ());
2417 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2419 copy.sort (RegionSortByLastLayerOp ());
2424 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2426 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2427 (*i)->set_pending_explicit_relayer (false);
2429 /* find the time divisions that this region covers; if there are no regions on the list,
2430 division_size will equal 0 and in this case we'll just say that
2431 start_division = end_division = 0.
2433 int start_division = 0;
2434 int end_division = 0;
2436 if (division_size > 0) {
2437 start_division = floor ( ((*i)->position() - start) / division_size);
2438 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2439 if (end_division == divisions) {
2444 assert (divisions == 0 || end_division < divisions);
2446 /* find the lowest layer that this region can go on */
2447 size_t j = layers.size();
2449 /* try layer j - 1; it can go on if it overlaps no other region
2450 that is already on that layer
2453 bool overlap = false;
2454 for (int k = start_division; k <= end_division; ++k) {
2455 RegionList::iterator l = layers[j-1][k].begin ();
2456 while (l != layers[j-1][k].end()) {
2457 if ((*l)->overlap_equivalent (*i)) {
2470 /* overlap, so we must use layer j */
2477 if (j == layers.size()) {
2478 /* we need a new layer for this region */
2479 layers.push_back (vector<RegionList> (divisions));
2482 /* put a reference to this region in each of the divisions that it exists in */
2483 for (int k = start_division; k <= end_division; ++k) {
2484 layers[j][k].push_back (*i);
2487 if ((*i)->layer() != j) {
2491 (*i)->set_layer (j);
2495 notify_layering_changed ();
2499 /* XXX these layer functions are all deprecated */
2502 Playlist::raise_region (boost::shared_ptr<Region> region)
2504 uint32_t top = regions.size() - 1;
2505 layer_t target = region->layer() + 1U;
2507 if (target >= top) {
2508 /* its already at the effective top */
2512 move_region_to_layer (target, region, 1);
2516 Playlist::lower_region (boost::shared_ptr<Region> region)
2518 if (region->layer() == 0) {
2519 /* its already at the bottom */
2523 layer_t target = region->layer() - 1U;
2525 move_region_to_layer (target, region, -1);
2529 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2531 /* does nothing useful if layering mode is later=higher */
2532 switch (_session.config.get_layer_model()) {
2539 layer_t top = regions.size() - 1;
2541 if (region->layer() >= top) {
2542 /* already on the top */
2546 move_region_to_layer (top, region, 1);
2547 /* mark the region's last_layer_op as now, so that it remains on top when
2548 doing future relayers (until something else takes over)
2550 timestamp_layer_op (region);
2554 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2556 /* does nothing useful if layering mode is later=higher */
2557 switch (_session.config.get_layer_model()) {
2564 if (region->layer() == 0) {
2565 /* already on the bottom */
2569 move_region_to_layer (0, region, -1);
2570 /* force region's last layer op to zero so that it stays at the bottom
2571 when doing future relayers
2573 region->set_last_layer_op (0);
2577 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2579 RegionList::iterator i;
2580 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2581 list<LayerInfo> layerinfo;
2584 RegionLock rlock (const_cast<Playlist *> (this));
2586 for (i = regions.begin(); i != regions.end(); ++i) {
2596 /* region is moving up, move all regions on intermediate layers
2600 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2601 dest = (*i)->layer() - 1;
2608 /* region is moving down, move all regions on intermediate layers
2612 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2613 dest = (*i)->layer() + 1;
2623 newpair.second = dest;
2625 layerinfo.push_back (newpair);
2631 /* now reset the layers without holding the region lock */
2633 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2634 x->first->set_layer (x->second);
2637 region->set_layer (target_layer);
2639 /* now check all dependents, since we changed the layering */
2641 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2642 check_dependents (x->first, false);
2645 check_dependents (region, false);
2646 notify_layering_changed ();
2654 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2656 RegionList::iterator i;
2662 RegionLock rlock (const_cast<Playlist *> (this));
2664 for (i = regions.begin(); i != regions.end(); ++i) {
2666 if ((*i)->position() >= start) {
2672 if ((*i)->last_frame() > max_framepos - distance) {
2673 new_pos = max_framepos - (*i)->length();
2675 new_pos = (*i)->position() + distance;
2680 if ((*i)->position() > distance) {
2681 new_pos = (*i)->position() - distance;
2687 (*i)->set_position (new_pos, this);
2695 notify_length_changed ();
2700 boost::shared_ptr<Region>
2701 Playlist::find_region (const ID& id) const
2703 RegionLock rlock (const_cast<Playlist*> (this));
2705 /* searches all regions currently in use by the playlist */
2707 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2708 if ((*i)->id() == id) {
2713 return boost::shared_ptr<Region> ();
2717 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2719 RegionLock rlock (const_cast<Playlist*> (this));
2722 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2731 boost::shared_ptr<Region>
2732 Playlist::region_by_id (const ID& id) const
2734 /* searches all regions ever added to this playlist */
2736 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2737 if ((*i)->id() == id) {
2741 return boost::shared_ptr<Region> ();
2745 Playlist::dump () const
2747 boost::shared_ptr<Region> r;
2749 cerr << "Playlist \"" << _name << "\" " << endl
2750 << regions.size() << " regions "
2753 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2755 cerr << " " << r->name() << " ["
2756 << r->start() << "+" << r->length()
2766 Playlist::set_frozen (bool yn)
2772 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2774 region->set_last_layer_op (++layer_op_counter);
2779 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2783 if (region->locked()) {
2790 RegionLock rlock (const_cast<Playlist*> (this));
2795 RegionList::iterator next;
2797 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2798 if ((*i) == region) {
2802 if (next != regions.end()) {
2804 if ((*next)->locked()) {
2810 if ((*next)->position() != region->last_frame() + 1) {
2811 /* they didn't used to touch, so after shuffle,
2812 just have them swap positions.
2814 new_pos = (*next)->position();
2816 /* they used to touch, so after shuffle,
2817 make sure they still do. put the earlier
2818 region where the later one will end after
2821 new_pos = region->position() + (*next)->length();
2824 (*next)->set_position (region->position(), this);
2825 region->set_position (new_pos, this);
2827 /* avoid a full sort */
2829 regions.erase (i); // removes the region from the list */
2831 regions.insert (next, region); // adds it back after next
2840 RegionList::iterator prev = regions.end();
2842 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2843 if ((*i) == region) {
2845 if (prev != regions.end()) {
2847 if ((*prev)->locked()) {
2852 if (region->position() != (*prev)->last_frame() + 1) {
2853 /* they didn't used to touch, so after shuffle,
2854 just have them swap positions.
2856 new_pos = region->position();
2858 /* they used to touch, so after shuffle,
2859 make sure they still do. put the earlier
2860 one where the later one will end after
2862 new_pos = (*prev)->position() + region->length();
2865 region->set_position ((*prev)->position(), this);
2866 (*prev)->set_position (new_pos, this);
2868 /* avoid a full sort */
2870 regions.erase (i); // remove region
2871 regions.insert (prev, region); // insert region before prev
2887 check_dependents (region, false);
2889 notify_contents_changed();
2895 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2897 RegionLock rlock (const_cast<Playlist*> (this));
2899 if (regions.size() > 1) {
2907 Playlist::update_after_tempo_map_change ()
2909 RegionLock rlock (const_cast<Playlist*> (this));
2910 RegionList copy (regions.rlist());
2914 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2915 (*i)->update_position_after_tempo_map_change ();
2922 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2924 RegionLock rl (this, false);
2925 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2931 Playlist::set_explicit_relayering (bool e)
2933 if (e == false && _explicit_relayering == true) {
2935 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2936 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2937 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2938 at this point would keep regions on the same layers.
2940 From then on in, it's just you and your towel.
2943 RegionLock rl (this);
2944 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2945 (*i)->set_last_layer_op ((*i)->layer ());
2949 _explicit_relayering = e;
2954 Playlist::has_region_at (framepos_t const p) const
2956 RegionLock (const_cast<Playlist *> (this));
2958 RegionList::const_iterator i = regions.begin ();
2959 while (i != regions.end() && !(*i)->covers (p)) {
2963 return (i != regions.end());
2966 /** Remove any region that uses a given source */
2968 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
2970 RegionLock rl (this);
2972 RegionList::iterator i = regions.begin();
2973 while (i != regions.end()) {
2974 RegionList::iterator j = i;
2977 if ((*i)->uses_source (s)) {
2978 remove_region_internal (*i);