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 cerr << "Playlist: region added at " << position << endl;
782 possibly_splice_unlocked (position, region->length(), region);
784 cerr << "Playlist: post-splice, region @ " << region->position() << endl;
786 if (!holding_state ()) {
787 /* layers get assigned from XML state, and are not reset during undo/redo */
791 /* we need to notify the existence of new region before checking dependents. Ick. */
793 notify_region_added (region);
795 if (!holding_state ()) {
797 check_dependents (region, false);
799 if (old_length != _get_extent().second) {
800 notify_length_changed ();
804 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
810 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
812 RegionLock rlock (this);
814 bool old_sp = _splicing;
817 remove_region_internal (old);
818 add_region_internal (newr, pos);
822 possibly_splice_unlocked (pos, old->length() - newr->length());
826 Playlist::remove_region (boost::shared_ptr<Region> region)
828 RegionLock rlock (this);
829 remove_region_internal (region);
833 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
835 RegionList::iterator i;
836 framecnt_t old_length = 0;
839 if (!holding_state()) {
840 old_length = _get_extent().second;
845 region->set_playlist (boost::weak_ptr<Playlist>());
848 /* XXX should probably freeze here .... */
850 for (i = regions.begin(); i != regions.end(); ++i) {
853 framepos_t pos = (*i)->position();
854 framecnt_t distance = (*i)->length();
858 possibly_splice_unlocked (pos, -distance);
860 if (!holding_state ()) {
862 remove_dependents (region);
864 if (old_length != _get_extent().second) {
865 notify_length_changed ();
869 notify_region_removed (region);
879 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
881 if (Config->get_use_overlap_equivalency()) {
882 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
883 if ((*i)->overlap_equivalent (other)) {
884 results.push_back ((*i));
888 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
889 if ((*i)->equivalent (other)) {
890 results.push_back ((*i));
897 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
899 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
901 if ((*i) && (*i)->region_list_equivalent (other)) {
902 results.push_back (*i);
908 Playlist::partition (framepos_t start, framepos_t end, bool cut)
912 partition_internal (start, end, cut, thawlist);
914 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
915 (*i)->resume_property_changes ();
920 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
922 RegionList new_regions;
925 RegionLock rlock (this);
927 boost::shared_ptr<Region> region;
928 boost::shared_ptr<Region> current;
930 RegionList::iterator tmp;
932 framepos_t pos1, pos2, pos3, pos4;
936 /* need to work from a copy, because otherwise the regions we add during the process
937 get operated on as well.
940 RegionList copy = regions.rlist();
942 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
949 if (current->first_frame() >= start && current->last_frame() < end) {
952 remove_region_internal (current);
958 /* coverage will return OverlapStart if the start coincides
959 with the end point. we do not partition such a region,
960 so catch this special case.
963 if (current->first_frame() >= end) {
967 if ((overlap = current->coverage (start, end)) == OverlapNone) {
971 pos1 = current->position();
974 pos4 = current->last_frame();
976 if (overlap == OverlapInternal) {
977 /* split: we need 3 new regions, the front, middle and end.
978 cut: we need 2 regions, the front and end.
983 ---------------*************************------------
986 ---------------*****++++++++++++++++====------------
988 ---------------*****----------------====------------
993 /* "middle" ++++++ */
995 RegionFactory::region_name (new_name, current->name(), false);
999 plist.add (Properties::start, current->start() + (pos2 - pos1));
1000 plist.add (Properties::length, pos3 - pos2);
1001 plist.add (Properties::name, new_name);
1002 plist.add (Properties::layer, regions.size());
1003 plist.add (Properties::automatic, true);
1004 plist.add (Properties::left_of_split, true);
1005 plist.add (Properties::right_of_split, true);
1007 region = RegionFactory::create (current, plist);
1008 add_region_internal (region, start);
1009 new_regions.push_back (region);
1014 RegionFactory::region_name (new_name, current->name(), false);
1018 plist.add (Properties::start, current->start() + (pos3 - pos1));
1019 plist.add (Properties::length, pos4 - pos3);
1020 plist.add (Properties::name, new_name);
1021 plist.add (Properties::layer, regions.size());
1022 plist.add (Properties::automatic, true);
1023 plist.add (Properties::right_of_split, true);
1025 region = RegionFactory::create (current, plist);
1027 add_region_internal (region, end);
1028 new_regions.push_back (region);
1032 current->suspend_property_changes ();
1033 thawlist.push_back (current);
1034 current->cut_end (pos2 - 1, this);
1036 } else if (overlap == OverlapEnd) {
1040 ---------------*************************------------
1043 ---------------**************+++++++++++------------
1045 ---------------**************-----------------------
1052 RegionFactory::region_name (new_name, current->name(), false);
1056 plist.add (Properties::start, current->start() + (pos2 - pos1));
1057 plist.add (Properties::length, pos4 - pos2);
1058 plist.add (Properties::name, new_name);
1059 plist.add (Properties::layer, regions.size());
1060 plist.add (Properties::automatic, true);
1061 plist.add (Properties::left_of_split, true);
1063 region = RegionFactory::create (current, plist);
1065 add_region_internal (region, start);
1066 new_regions.push_back (region);
1071 current->suspend_property_changes ();
1072 thawlist.push_back (current);
1073 current->cut_end (pos2 - 1, this);
1075 } else if (overlap == OverlapStart) {
1077 /* split: we need 2 regions: the front and the end.
1078 cut: just trim current to skip the cut area
1083 ---------------*************************------------
1087 ---------------****+++++++++++++++++++++------------
1089 -------------------*********************------------
1095 RegionFactory::region_name (new_name, current->name(), false);
1099 plist.add (Properties::start, current->start());
1100 plist.add (Properties::length, pos3 - pos1);
1101 plist.add (Properties::name, new_name);
1102 plist.add (Properties::layer, regions.size());
1103 plist.add (Properties::automatic, true);
1104 plist.add (Properties::right_of_split, true);
1106 region = RegionFactory::create (current, plist);
1108 add_region_internal (region, pos1);
1109 new_regions.push_back (region);
1114 current->suspend_property_changes ();
1115 thawlist.push_back (current);
1116 current->trim_front (pos3, this);
1117 } else if (overlap == OverlapExternal) {
1119 /* split: no split required.
1120 cut: remove the region.
1125 ---------------*************************------------
1129 ---------------*************************------------
1131 ----------------------------------------------------
1136 remove_region_internal (current);
1139 new_regions.push_back (current);
1143 in_partition = false;
1146 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1147 check_dependents (*i, false);
1151 boost::shared_ptr<Playlist>
1152 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1154 boost::shared_ptr<Playlist> ret;
1155 boost::shared_ptr<Playlist> pl;
1158 if (ranges.empty()) {
1159 return boost::shared_ptr<Playlist>();
1162 start = ranges.front().start;
1164 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1166 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1168 if (i == ranges.begin()) {
1172 /* paste the next section into the nascent playlist,
1173 offset to reflect the start of the first range we
1177 ret->paste (pl, (*i).start - start, 1.0f);
1184 boost::shared_ptr<Playlist>
1185 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1187 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1188 return cut_copy (pmf, ranges, result_is_hidden);
1191 boost::shared_ptr<Playlist>
1192 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1194 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1195 return cut_copy (pmf, ranges, result_is_hidden);
1198 boost::shared_ptr<Playlist>
1199 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1201 boost::shared_ptr<Playlist> the_copy;
1202 RegionList thawlist;
1205 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1206 string new_name = _name;
1210 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1211 return boost::shared_ptr<Playlist>();
1214 partition_internal (start, start+cnt-1, true, thawlist);
1216 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1217 (*i)->resume_property_changes();
1223 boost::shared_ptr<Playlist>
1224 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1228 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1229 string new_name = _name;
1233 cnt = min (_get_extent().second - start, cnt);
1234 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1238 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1240 times = fabs (times);
1243 RegionLock rl1 (this);
1244 RegionLock rl2 (other.get());
1246 framecnt_t const old_length = _get_extent().second;
1248 int itimes = (int) floor (times);
1249 framepos_t pos = position;
1250 framecnt_t const shift = other->_get_extent().second;
1251 layer_t top_layer = regions.size();
1254 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1255 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1257 /* put these new regions on top of all existing ones, but preserve
1258 the ordering they had in the original playlist.
1261 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1262 cerr << "DEBUG: add new region at " << pos << endl;
1263 add_region_internal (copy_of_region, (*i)->position() + pos);
1269 /* XXX shall we handle fractional cases at some point? */
1271 if (old_length != _get_extent().second) {
1272 notify_length_changed ();
1283 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1285 times = fabs (times);
1287 RegionLock rl (this);
1288 int itimes = (int) floor (times);
1289 framepos_t pos = position + 1;
1292 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1293 add_region_internal (copy, pos);
1294 pos += region->length();
1297 if (floor (times) != times) {
1298 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1300 RegionFactory::region_name (name, region->name(), false);
1305 plist.add (Properties::start, region->start());
1306 plist.add (Properties::length, length);
1307 plist.add (Properties::name, name);
1309 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1310 add_region_internal (sub, pos);
1316 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1318 RegionLock rlock (this);
1319 RegionList copy (regions.rlist());
1322 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1324 if ((*r)->last_frame() < at) {
1329 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1330 /* intersected region */
1331 if (!move_intersected) {
1336 /* do not move regions glued to music time - that
1337 has to be done separately.
1340 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1341 fixup.push_back (*r);
1345 (*r)->set_position ((*r)->position() + distance, this);
1348 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1349 (*r)->recompute_position_from_lock_style ();
1354 Playlist::split (framepos_t at)
1356 RegionLock rlock (this);
1357 RegionList copy (regions.rlist());
1359 /* use a copy since this operation can modify the region list
1362 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1363 _split_region (*r, at);
1368 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1370 RegionLock rl (this);
1371 _split_region (region, playlist_position);
1375 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1377 if (!region->covers (playlist_position)) {
1381 if (region->position() == playlist_position ||
1382 region->last_frame() == playlist_position) {
1386 boost::shared_ptr<Region> left;
1387 boost::shared_ptr<Region> right;
1388 frameoffset_t before;
1389 frameoffset_t after;
1393 /* split doesn't change anything about length, so don't try to splice */
1395 bool old_sp = _splicing;
1398 before = playlist_position - region->position();
1399 after = region->length() - before;
1401 RegionFactory::region_name (before_name, region->name(), false);
1406 plist.add (Properties::position, region->position ());
1407 plist.add (Properties::length, before);
1408 plist.add (Properties::name, before_name);
1409 plist.add (Properties::left_of_split, true);
1411 /* note: we must use the version of ::create with an offset here,
1412 since it supplies that offset to the Region constructor, which
1413 is necessary to get audio region gain envelopes right.
1415 left = RegionFactory::create (region, 0, plist);
1418 RegionFactory::region_name (after_name, region->name(), false);
1423 plist.add (Properties::position, region->position() + before);
1424 plist.add (Properties::length, after);
1425 plist.add (Properties::name, after_name);
1426 plist.add (Properties::right_of_split, true);
1428 /* same note as above */
1429 right = RegionFactory::create (region, before, plist);
1432 add_region_internal (left, region->position());
1433 add_region_internal (right, region->position() + before);
1435 uint64_t orig_layer_op = region->last_layer_op();
1436 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1437 if ((*i)->last_layer_op() > orig_layer_op) {
1438 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1442 left->set_last_layer_op ( orig_layer_op );
1443 right->set_last_layer_op ( orig_layer_op + 1);
1447 finalize_split_region (region, left, right);
1449 remove_region_internal (region);
1455 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1457 if (_splicing || in_set_state) {
1458 /* don't respond to splicing moves or state setting */
1462 if (_edit_mode == Splice) {
1463 splice_locked (at, distance, exclude);
1468 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1470 if (_splicing || in_set_state) {
1471 /* don't respond to splicing moves or state setting */
1475 if (_edit_mode == Splice) {
1476 splice_unlocked (at, distance, exclude);
1481 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1484 RegionLock rl (this);
1485 core_splice (at, distance, exclude);
1490 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1492 core_splice (at, distance, exclude);
1496 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1500 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1502 if (exclude && (*i) == exclude) {
1506 if ((*i)->position() >= at) {
1507 framepos_t new_pos = (*i)->position() + distance;
1510 } else if (new_pos >= max_framepos - (*i)->length()) {
1511 new_pos = max_framepos - (*i)->length();
1514 (*i)->set_position (new_pos, this);
1520 notify_length_changed ();
1524 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1526 if (in_set_state || _splicing || _nudging || _shuffling) {
1530 if (what_changed.contains (Properties::position)) {
1532 /* remove it from the list then add it back in
1533 the right place again.
1536 RegionSortByPosition cmp;
1538 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1540 if (i == regions.end()) {
1541 /* the region bounds are being modified but its not currently
1542 in the region list. we will use its bounds correctly when/if
1549 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1552 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1554 frameoffset_t delta = 0;
1556 if (what_changed.contains (Properties::position)) {
1557 delta = region->position() - region->last_position();
1560 if (what_changed.contains (Properties::length)) {
1561 delta += region->length() - region->last_length();
1565 possibly_splice (region->last_position() + region->last_length(), delta, region);
1568 if (holding_state ()) {
1569 pending_bounds.push_back (region);
1571 if (_session.config.get_layer_model() == MoveAddHigher) {
1572 /* it moved or changed length, so change the timestamp */
1573 timestamp_layer_op (region);
1576 notify_length_changed ();
1578 check_dependents (region, false);
1584 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1586 boost::shared_ptr<Region> region (weak_region.lock());
1592 /* this makes a virtual call to the right kind of playlist ... */
1594 region_changed (what_changed, region);
1598 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1600 PropertyChange our_interests;
1601 PropertyChange bounds;
1602 PropertyChange pos_and_length;
1605 if (in_set_state || in_flush) {
1609 our_interests.add (Properties::muted);
1610 our_interests.add (Properties::layer);
1611 our_interests.add (Properties::opaque);
1613 bounds.add (Properties::start);
1614 bounds.add (Properties::position);
1615 bounds.add (Properties::length);
1617 pos_and_length.add (Properties::position);
1618 pos_and_length.add (Properties::length);
1620 if (what_changed.contains (bounds)) {
1621 region_bounds_changed (what_changed, region);
1622 save = !(_splicing || _nudging);
1625 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1626 check_dependents (region, false);
1629 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1630 notify_region_moved (region);
1634 /* don't notify about layer changes, since we are the only object that can initiate
1635 them, and we notify in ::relayer()
1638 if (what_changed.contains (our_interests)) {
1646 Playlist::drop_regions ()
1648 RegionLock rl (this);
1650 all_regions.clear ();
1654 Playlist::clear (bool with_signals)
1657 RegionLock rl (this);
1659 region_state_changed_connections.drop_connections ();
1661 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1662 pending_removes.insert (*i);
1667 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1668 remove_dependents (*s);
1674 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1675 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1678 pending_removes.clear ();
1679 pending_length = false;
1681 pending_contents_change = false;
1687 /***********************************************************************
1689 **********************************************************************/
1691 Playlist::RegionList *
1692 Playlist::regions_at (framepos_t frame)
1695 RegionLock rlock (this);
1696 return find_regions_at (frame);
1700 Playlist::count_regions_at (framepos_t frame)
1702 RegionLock rlock (this);
1705 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1706 if ((*i)->covers (frame)) {
1714 boost::shared_ptr<Region>
1715 Playlist::top_region_at (framepos_t frame)
1718 RegionLock rlock (this);
1719 RegionList *rlist = find_regions_at (frame);
1720 boost::shared_ptr<Region> region;
1722 if (rlist->size()) {
1723 RegionSortByLayer cmp;
1725 region = rlist->back();
1732 boost::shared_ptr<Region>
1733 Playlist::top_unmuted_region_at (framepos_t frame)
1736 RegionLock rlock (this);
1737 RegionList *rlist = find_regions_at (frame);
1739 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1741 RegionList::iterator tmp = i;
1744 if ((*i)->muted()) {
1751 boost::shared_ptr<Region> region;
1753 if (rlist->size()) {
1754 RegionSortByLayer cmp;
1756 region = rlist->back();
1763 Playlist::RegionList*
1764 Playlist::regions_to_read (framepos_t start, framepos_t end)
1766 /* Caller must hold lock */
1768 RegionList covering;
1769 set<framepos_t> to_check;
1770 set<boost::shared_ptr<Region> > unique;
1772 to_check.insert (start);
1773 to_check.insert (end);
1775 DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1777 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1779 /* find all/any regions that span start+end */
1781 switch ((*i)->coverage (start, end)) {
1785 case OverlapInternal:
1786 covering.push_back (*i);
1787 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1791 to_check.insert ((*i)->position());
1792 if ((*i)->position() != 0) {
1793 to_check.insert ((*i)->position()-1);
1795 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1796 covering.push_back (*i);
1800 to_check.insert ((*i)->last_frame());
1801 to_check.insert ((*i)->last_frame()+1);
1802 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1803 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1804 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1805 covering.push_back (*i);
1808 case OverlapExternal:
1809 covering.push_back (*i);
1810 to_check.insert ((*i)->position());
1811 if ((*i)->position() != 0) {
1812 to_check.insert ((*i)->position()-1);
1814 to_check.insert ((*i)->last_frame());
1815 to_check.insert ((*i)->last_frame()+1);
1816 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1817 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1818 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1822 /* don't go too far */
1824 if ((*i)->position() > end) {
1829 RegionList* rlist = new RegionList;
1831 /* find all the regions that cover each position .... */
1833 if (covering.size() == 1) {
1835 rlist->push_back (covering.front());
1836 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1841 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1845 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1847 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1849 if ((*x)->covers (*t)) {
1850 here.push_back (*x);
1851 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1855 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1862 RegionSortByLayer cmp;
1865 /* ... and get the top/transparent regions at "here" */
1867 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1871 if ((*c)->opaque()) {
1873 /* the other regions at this position are hidden by this one */
1874 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1881 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1882 rlist->push_back (*s);
1885 if (rlist->size() > 1) {
1886 /* now sort by time order */
1888 RegionSortByPosition cmp;
1893 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1898 Playlist::RegionList *
1899 Playlist::find_regions_at (framepos_t frame)
1901 /* Caller must hold lock */
1903 RegionList *rlist = new RegionList;
1905 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1906 if ((*i)->covers (frame)) {
1907 rlist->push_back (*i);
1914 Playlist::RegionList *
1915 Playlist::regions_touched (framepos_t start, framepos_t end)
1917 RegionLock rlock (this);
1918 RegionList *rlist = new RegionList;
1920 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1921 if ((*i)->coverage (start, end) != OverlapNone) {
1922 rlist->push_back (*i);
1930 Playlist::find_next_transient (framepos_t from, int dir)
1932 RegionLock rlock (this);
1933 AnalysisFeatureList points;
1934 AnalysisFeatureList these_points;
1936 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1938 if ((*i)->last_frame() < from) {
1942 if ((*i)->first_frame() > from) {
1947 (*i)->get_transients (these_points);
1949 /* add first frame, just, err, because */
1951 these_points.push_back ((*i)->first_frame());
1953 points.insert (points.end(), these_points.begin(), these_points.end());
1954 these_points.clear ();
1957 if (points.empty()) {
1961 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1962 bool reached = false;
1965 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1970 if (reached && (*x) > from) {
1975 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1980 if (reached && (*x) < from) {
1989 boost::shared_ptr<Region>
1990 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1992 RegionLock rlock (this);
1993 boost::shared_ptr<Region> ret;
1994 framepos_t closest = max_framepos;
1996 bool end_iter = false;
1998 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2002 frameoffset_t distance;
2003 boost::shared_ptr<Region> r = (*i);
2008 pos = r->first_frame ();
2011 pos = r->last_frame ();
2014 pos = r->sync_position ();
2019 case 1: /* forwards */
2022 if ((distance = pos - frame) < closest) {
2031 default: /* backwards */
2034 if ((distance = frame - pos) < closest) {
2051 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2053 RegionLock rlock (this);
2055 framepos_t closest = max_framepos;
2056 framepos_t ret = -1;
2060 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2062 boost::shared_ptr<Region> r = (*i);
2063 frameoffset_t distance;
2065 if (r->first_frame() > frame) {
2067 distance = r->first_frame() - frame;
2069 if (distance < closest) {
2070 ret = r->first_frame();
2075 if (r->last_frame () > frame) {
2077 distance = r->last_frame () - frame;
2079 if (distance < closest) {
2080 ret = r->last_frame ();
2088 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2090 boost::shared_ptr<Region> r = (*i);
2091 frameoffset_t distance;
2093 if (r->last_frame() < frame) {
2095 distance = frame - r->last_frame();
2097 if (distance < closest) {
2098 ret = r->last_frame();
2103 if (r->first_frame() < frame) {
2105 distance = frame - r->first_frame();
2107 if (distance < closest) {
2108 ret = r->first_frame();
2119 /***********************************************************************/
2125 Playlist::mark_session_dirty ()
2127 if (!in_set_state && !holding_state ()) {
2128 _session.set_dirty();
2133 Playlist::rdiff (vector<Command*>& cmds) const
2135 RegionLock rlock (const_cast<Playlist *> (this));
2136 Stateful::rdiff (cmds);
2140 Playlist::clear_owned_changes ()
2142 RegionLock rlock (this);
2143 Stateful::clear_owned_changes ();
2147 Playlist::update (const RegionListProperty::ChangeRecord& change)
2149 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2150 name(), change.added.size(), change.removed.size()));
2153 /* add the added regions */
2154 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2155 add_region ((*i), (*i)->position());
2157 /* remove the removed regions */
2158 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2166 Playlist::set_state (const XMLNode& node, int version)
2170 XMLNodeConstIterator niter;
2171 XMLPropertyList plist;
2172 XMLPropertyConstIterator piter;
2174 boost::shared_ptr<Region> region;
2179 if (node.name() != "Playlist") {
2186 plist = node.properties();
2188 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2192 if (prop->name() == X_("name")) {
2193 _name = prop->value();
2195 } else if (prop->name() == X_("id")) {
2196 _id = prop->value();
2197 } else if (prop->name() == X_("orig_diskstream_id")) {
2198 _orig_diskstream_id = prop->value ();
2199 } else if (prop->name() == X_("frozen")) {
2200 _frozen = string_is_affirmative (prop->value());
2206 nlist = node.children();
2208 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2212 if (child->name() == "Region") {
2214 if ((prop = child->property ("id")) == 0) {
2215 error << _("region state node has no ID, ignored") << endmsg;
2219 ID id = prop->value ();
2221 if ((region = region_by_id (id))) {
2223 region->suspend_property_changes ();
2225 if (region->set_state (*child, version)) {
2226 region->resume_property_changes ();
2230 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2231 region->suspend_property_changes ();
2233 error << _("Playlist: cannot create region from XML") << endmsg;
2238 add_region (region, region->position(), 1.0);
2240 // So that layer_op ordering doesn't get screwed up
2241 region->set_last_layer_op( region->layer());
2242 region->resume_property_changes ();
2246 /* update dependents, which was not done during add_region_internal
2247 due to in_set_state being true
2250 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2251 check_dependents (*r, false);
2255 notify_contents_changed ();
2258 first_set_state = false;
2263 Playlist::get_state()
2265 return state (true);
2269 Playlist::get_template()
2271 return state (false);
2274 /** @param full_state true to include regions in the returned state, otherwise false.
2277 Playlist::state (bool full_state)
2279 XMLNode *node = new XMLNode (X_("Playlist"));
2282 node->add_property (X_("id"), id().to_s());
2283 node->add_property (X_("name"), _name);
2284 node->add_property (X_("type"), _type.to_string());
2286 _orig_diskstream_id.print (buf, sizeof (buf));
2287 node->add_property (X_("orig_diskstream_id"), buf);
2288 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2291 RegionLock rlock (this, false);
2293 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2294 node->add_child_nocopy ((*i)->get_state());
2299 node->add_child_copy (*_extra_xml);
2306 Playlist::empty() const
2308 RegionLock rlock (const_cast<Playlist *>(this), false);
2309 return regions.empty();
2313 Playlist::n_regions() const
2315 RegionLock rlock (const_cast<Playlist *>(this), false);
2316 return regions.size();
2319 pair<framepos_t, framepos_t>
2320 Playlist::get_extent () const
2322 RegionLock rlock (const_cast<Playlist *>(this), false);
2323 return _get_extent ();
2326 pair<framepos_t, framepos_t>
2327 Playlist::_get_extent () const
2329 pair<framepos_t, framepos_t> ext (max_framepos, 0);
2331 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2332 pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2333 if (e.first < ext.first) {
2334 ext.first = e.first;
2336 if (e.second > ext.second) {
2337 ext.second = e.second;
2345 Playlist::bump_name (string name, Session &session)
2347 string newname = name;
2350 newname = bump_name_once (newname, '.');
2351 } while (session.playlists->by_name (newname)!=NULL);
2358 Playlist::top_layer() const
2360 RegionLock rlock (const_cast<Playlist *> (this));
2363 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2364 top = max (top, (*i)->layer());
2370 Playlist::set_edit_mode (EditMode mode)
2375 /********************
2377 ********************/
2380 Playlist::relayer ()
2382 /* never compute layers when changing state for undo/redo or setting from XML */
2384 if (in_update || in_set_state) {
2388 bool changed = false;
2390 /* Build up a new list of regions on each layer, stored in a set of lists
2391 each of which represent some period of time on some layer. The idea
2392 is to avoid having to search the entire region list to establish whether
2393 each region overlaps another */
2395 /* how many pieces to divide this playlist's time up into */
2396 int const divisions = 512;
2398 /* find the start and end positions of the regions on this playlist */
2399 framepos_t start = INT64_MAX;
2401 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2402 start = min (start, (*i)->position());
2403 end = max (end, (*i)->position() + (*i)->length());
2406 /* hence the size of each time division */
2407 double const division_size = (end - start) / double (divisions);
2409 vector<vector<RegionList> > layers;
2410 layers.push_back (vector<RegionList> (divisions));
2412 /* we want to go through regions from desired lowest to desired highest layer,
2413 which depends on the layer model
2416 RegionList copy = regions.rlist();
2418 /* sort according to the model and the layering mode that we're in */
2420 if (_explicit_relayering) {
2422 copy.sort (RegionSortByLayerWithPending ());
2424 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2426 copy.sort (RegionSortByLastLayerOp ());
2431 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2433 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2434 (*i)->set_pending_explicit_relayer (false);
2436 /* find the time divisions that this region covers; if there are no regions on the list,
2437 division_size will equal 0 and in this case we'll just say that
2438 start_division = end_division = 0.
2440 int start_division = 0;
2441 int end_division = 0;
2443 if (division_size > 0) {
2444 start_division = floor ( ((*i)->position() - start) / division_size);
2445 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2446 if (end_division == divisions) {
2451 assert (divisions == 0 || end_division < divisions);
2453 /* find the lowest layer that this region can go on */
2454 size_t j = layers.size();
2456 /* try layer j - 1; it can go on if it overlaps no other region
2457 that is already on that layer
2460 bool overlap = false;
2461 for (int k = start_division; k <= end_division; ++k) {
2462 RegionList::iterator l = layers[j-1][k].begin ();
2463 while (l != layers[j-1][k].end()) {
2464 if ((*l)->overlap_equivalent (*i)) {
2477 /* overlap, so we must use layer j */
2484 if (j == layers.size()) {
2485 /* we need a new layer for this region */
2486 layers.push_back (vector<RegionList> (divisions));
2489 /* put a reference to this region in each of the divisions that it exists in */
2490 for (int k = start_division; k <= end_division; ++k) {
2491 layers[j][k].push_back (*i);
2494 if ((*i)->layer() != j) {
2498 (*i)->set_layer (j);
2502 notify_layering_changed ();
2506 /* XXX these layer functions are all deprecated */
2509 Playlist::raise_region (boost::shared_ptr<Region> region)
2511 uint32_t top = regions.size() - 1;
2512 layer_t target = region->layer() + 1U;
2514 if (target >= top) {
2515 /* its already at the effective top */
2519 move_region_to_layer (target, region, 1);
2523 Playlist::lower_region (boost::shared_ptr<Region> region)
2525 if (region->layer() == 0) {
2526 /* its already at the bottom */
2530 layer_t target = region->layer() - 1U;
2532 move_region_to_layer (target, region, -1);
2536 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2538 /* does nothing useful if layering mode is later=higher */
2539 switch (_session.config.get_layer_model()) {
2546 layer_t top = regions.size() - 1;
2548 if (region->layer() >= top) {
2549 /* already on the top */
2553 move_region_to_layer (top, region, 1);
2554 /* mark the region's last_layer_op as now, so that it remains on top when
2555 doing future relayers (until something else takes over)
2557 timestamp_layer_op (region);
2561 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2563 /* does nothing useful if layering mode is later=higher */
2564 switch (_session.config.get_layer_model()) {
2571 if (region->layer() == 0) {
2572 /* already on the bottom */
2576 move_region_to_layer (0, region, -1);
2577 /* force region's last layer op to zero so that it stays at the bottom
2578 when doing future relayers
2580 region->set_last_layer_op (0);
2584 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2586 RegionList::iterator i;
2587 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2588 list<LayerInfo> layerinfo;
2591 RegionLock rlock (const_cast<Playlist *> (this));
2593 for (i = regions.begin(); i != regions.end(); ++i) {
2603 /* region is moving up, move all regions on intermediate layers
2607 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2608 dest = (*i)->layer() - 1;
2615 /* region is moving down, move all regions on intermediate layers
2619 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2620 dest = (*i)->layer() + 1;
2630 newpair.second = dest;
2632 layerinfo.push_back (newpair);
2638 /* now reset the layers without holding the region lock */
2640 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2641 x->first->set_layer (x->second);
2644 region->set_layer (target_layer);
2646 /* now check all dependents, since we changed the layering */
2648 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2649 check_dependents (x->first, false);
2652 check_dependents (region, false);
2653 notify_layering_changed ();
2661 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2663 RegionList::iterator i;
2669 RegionLock rlock (const_cast<Playlist *> (this));
2671 for (i = regions.begin(); i != regions.end(); ++i) {
2673 if ((*i)->position() >= start) {
2679 if ((*i)->last_frame() > max_framepos - distance) {
2680 new_pos = max_framepos - (*i)->length();
2682 new_pos = (*i)->position() + distance;
2687 if ((*i)->position() > distance) {
2688 new_pos = (*i)->position() - distance;
2694 (*i)->set_position (new_pos, this);
2702 notify_length_changed ();
2707 boost::shared_ptr<Region>
2708 Playlist::find_region (const ID& id) const
2710 RegionLock rlock (const_cast<Playlist*> (this));
2712 /* searches all regions currently in use by the playlist */
2714 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2715 if ((*i)->id() == id) {
2720 return boost::shared_ptr<Region> ();
2724 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2726 RegionLock rlock (const_cast<Playlist*> (this));
2729 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2738 boost::shared_ptr<Region>
2739 Playlist::region_by_id (const ID& id) const
2741 /* searches all regions ever added to this playlist */
2743 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2744 if ((*i)->id() == id) {
2748 return boost::shared_ptr<Region> ();
2752 Playlist::dump () const
2754 boost::shared_ptr<Region> r;
2756 cerr << "Playlist \"" << _name << "\" " << endl
2757 << regions.size() << " regions "
2760 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2762 cerr << " " << r->name() << " ["
2763 << r->start() << "+" << r->length()
2773 Playlist::set_frozen (bool yn)
2779 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2781 region->set_last_layer_op (++layer_op_counter);
2786 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2790 if (region->locked()) {
2797 RegionLock rlock (const_cast<Playlist*> (this));
2802 RegionList::iterator next;
2804 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2805 if ((*i) == region) {
2809 if (next != regions.end()) {
2811 if ((*next)->locked()) {
2817 if ((*next)->position() != region->last_frame() + 1) {
2818 /* they didn't used to touch, so after shuffle,
2819 just have them swap positions.
2821 new_pos = (*next)->position();
2823 /* they used to touch, so after shuffle,
2824 make sure they still do. put the earlier
2825 region where the later one will end after
2828 new_pos = region->position() + (*next)->length();
2831 (*next)->set_position (region->position(), this);
2832 region->set_position (new_pos, this);
2834 /* avoid a full sort */
2836 regions.erase (i); // removes the region from the list */
2838 regions.insert (next, region); // adds it back after next
2847 RegionList::iterator prev = regions.end();
2849 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2850 if ((*i) == region) {
2852 if (prev != regions.end()) {
2854 if ((*prev)->locked()) {
2859 if (region->position() != (*prev)->last_frame() + 1) {
2860 /* they didn't used to touch, so after shuffle,
2861 just have them swap positions.
2863 new_pos = region->position();
2865 /* they used to touch, so after shuffle,
2866 make sure they still do. put the earlier
2867 one where the later one will end after
2869 new_pos = (*prev)->position() + region->length();
2872 region->set_position ((*prev)->position(), this);
2873 (*prev)->set_position (new_pos, this);
2875 /* avoid a full sort */
2877 regions.erase (i); // remove region
2878 regions.insert (prev, region); // insert region before prev
2894 check_dependents (region, false);
2896 notify_contents_changed();
2902 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2904 RegionLock rlock (const_cast<Playlist*> (this));
2906 if (regions.size() > 1) {
2914 Playlist::update_after_tempo_map_change ()
2916 RegionLock rlock (const_cast<Playlist*> (this));
2917 RegionList copy (regions.rlist());
2921 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2922 (*i)->update_position_after_tempo_map_change ();
2929 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2931 RegionLock rl (this, false);
2932 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2938 Playlist::set_explicit_relayering (bool e)
2940 if (e == false && _explicit_relayering == true) {
2942 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2943 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2944 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2945 at this point would keep regions on the same layers.
2947 From then on in, it's just you and your towel.
2950 RegionLock rl (this);
2951 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2952 (*i)->set_last_layer_op ((*i)->layer ());
2956 _explicit_relayering = e;
2961 Playlist::has_region_at (framepos_t const p) const
2963 RegionLock (const_cast<Playlist *> (this));
2965 RegionList::const_iterator i = regions.begin ();
2966 while (i != regions.end() && !(*i)->covers (p)) {
2970 return (i != regions.end());
2973 /** Remove any region that uses a given source */
2975 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
2977 RegionLock rl (this);
2979 RegionList::iterator i = regions.begin();
2980 while (i != regions.end()) {
2981 RegionList::iterator j = i;
2984 if ((*i)->uses_source (s)) {
2985 remove_region_internal (*i);
2992 /** Look from a session frame time and find the start time of the next region
2993 * which is on the top layer of this playlist.
2994 * @param t Time to look from.
2995 * @return Position of next top-layered region, or max_framepos if there isn't one.
2998 Playlist::find_next_top_layer_position (framepos_t t) const
3000 RegionLock rlock (const_cast<Playlist *> (this));
3002 layer_t const top = top_layer ();
3004 RegionList copy = regions.rlist ();
3005 copy.sort (RegionSortByPosition ());
3007 for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3008 if ((*i)->position() >= t && (*i)->layer() == top) {
3009 return (*i)->position();
3013 return max_framepos;