2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <boost/lexical_cast.hpp>
30 #include "pbd/failed_constructor.h"
31 #include "pbd/stateful_diff_command.h"
32 #include "pbd/xml++.h"
34 #include "ardour/debug.h"
35 #include "ardour/playlist.h"
36 #include "ardour/session.h"
37 #include "ardour/region.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/playlist_factory.h"
40 #include "ardour/transient_detector.h"
41 #include "ardour/session_playlists.h"
46 using namespace ARDOUR;
50 namespace Properties {
51 PBD::PropertyDescriptor<bool> regions;
55 struct ShowMeTheList {
56 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
58 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
60 boost::shared_ptr<Playlist> playlist;
64 struct RegionSortByLayer {
65 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
66 return a->layer() < b->layer();
70 struct RegionSortByLayerWithPending {
71 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
73 double p = a->layer ();
74 if (a->pending_explicit_relayer()) {
78 double q = b->layer ();
79 if (b->pending_explicit_relayer()) {
87 struct RegionSortByPosition {
88 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
89 return a->position() < b->position();
93 struct RegionSortByLastLayerOp {
94 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
95 return a->last_layer_op() < b->last_layer_op();
100 Playlist::make_property_quarks ()
102 Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
103 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n", Properties::regions.property_id));
106 RegionListProperty::RegionListProperty (Playlist& pl)
107 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
112 boost::shared_ptr<Region>
113 RegionListProperty::lookup_id (const ID& id)
115 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
118 ret = RegionFactory::region_by_id (id);
125 RegionListProperty::copy_for_history () const
127 RegionListProperty* copy = new RegionListProperty (_playlist);
128 /* this is all we need */
129 copy->_change = _change;
134 RegionListProperty::diff (PropertyList& before, PropertyList& after) const
137 RegionListProperty* a = copy_for_history ();
138 RegionListProperty* b = copy_for_history ();
140 b->invert_changes ();
147 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
148 : SessionObject(sess, nom)
153 first_set_state = false;
159 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
160 : SessionObject(sess, "unnamed playlist")
165 const XMLProperty* prop = node.property("type");
166 assert(!prop || DataType(prop->value()) == _type);
169 _name = "unnamed"; /* reset by set_state */
172 /* set state called by derived class */
175 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
176 : SessionObject(other->_session, namestr)
178 , _type(other->_type)
179 , _orig_diskstream_id(other->_orig_diskstream_id)
184 other->copy_regions (tmp);
188 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
189 add_region_internal( (*x), (*x)->position());
194 _splicing = other->_splicing;
195 _nudging = other->_nudging;
196 _edit_mode = other->_edit_mode;
199 first_set_state = false;
201 in_partition = false;
203 _read_data_count = 0;
204 _frozen = other->_frozen;
206 layer_op_counter = other->layer_op_counter;
207 freeze_length = other->freeze_length;
210 Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
211 : SessionObject(other->_session, str)
213 , _type(other->_type)
214 , _orig_diskstream_id(other->_orig_diskstream_id)
216 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
218 framepos_t end = start + cnt - 1;
224 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
226 boost::shared_ptr<Region> region;
227 boost::shared_ptr<Region> new_region;
228 frameoffset_t offset = 0;
229 framepos_t position = 0;
236 overlap = region->coverage (start, end);
242 case OverlapInternal:
243 offset = start - region->position();
250 position = region->position() - start;
251 len = end - region->position();
255 offset = start - region->position();
257 len = region->length() - offset;
260 case OverlapExternal:
262 position = region->position() - start;
263 len = region->length();
267 RegionFactory::region_name (new_name, region->name(), false);
271 plist.add (Properties::start, region->start() + offset);
272 plist.add (Properties::length, len);
273 plist.add (Properties::name, new_name);
274 plist.add (Properties::layer, region->layer());
276 new_region = RegionFactory::RegionFactory::create (region, plist);
278 add_region_internal (new_region, position);
282 first_set_state = false;
284 /* this constructor does NOT notify others (session) */
291 InUse (true); /* EMIT SIGNAL */
302 InUse (false); /* EMIT SIGNAL */
307 Playlist::copy_regions (RegionList& newlist) const
309 RegionLock rlock (const_cast<Playlist *> (this));
311 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
312 newlist.push_back (RegionFactory::RegionFactory::create (*i));
317 Playlist::init (bool hide)
319 add_property (regions);
320 _xml_node_name = X_("Playlist");
322 g_atomic_int_set (&block_notifications, 0);
323 g_atomic_int_set (&ignore_state_changes, 0);
324 pending_contents_change = false;
325 pending_length = false;
326 pending_layering = false;
327 first_set_state = true;
335 _edit_mode = Config->get_edit_mode();
337 in_partition = false;
339 _read_data_count = 0;
341 layer_op_counter = 0;
343 _explicit_relayering = false;
345 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
346 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
348 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
351 Playlist::~Playlist ()
353 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
356 RegionLock rl (this);
358 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
359 (*i)->set_playlist (boost::shared_ptr<Playlist>());
363 /* GoingAway must be emitted by derived classes */
367 Playlist::_set_sort_id ()
370 Playlists are given names like <track name>.<id>
371 or <track name>.<edit group name>.<id> where id
372 is an integer. We extract the id and sort by that.
375 size_t dot_position = _name.val().find_last_of(".");
377 if (dot_position == string::npos) {
380 string t = _name.val().substr(dot_position + 1);
383 _sort_id = boost::lexical_cast<int>(t);
386 catch (boost::bad_lexical_cast e) {
393 Playlist::set_name (const string& str)
395 /* in a typical situation, a playlist is being used
396 by one diskstream and also is referenced by the
397 Session. if there are more references than that,
398 then don't change the name.
405 bool ret = SessionObject::set_name(str);
412 /***********************************************************************
413 CHANGE NOTIFICATION HANDLING
415 Notifications must be delayed till the region_lock is released. This
416 is necessary because handlers for the signals may need to acquire
417 the lock (e.g. to read from the playlist).
418 ***********************************************************************/
421 Playlist::begin_undo ()
428 Playlist::end_undo ()
437 delay_notifications ();
438 g_atomic_int_inc (&ignore_state_changes);
444 g_atomic_int_dec_and_test (&ignore_state_changes);
445 release_notifications ();
450 Playlist::delay_notifications ()
452 g_atomic_int_inc (&block_notifications);
453 freeze_length = _get_maximum_extent();
457 Playlist::release_notifications ()
459 if (g_atomic_int_dec_and_test (&block_notifications)) {
460 flush_notifications ();
466 Playlist::notify_contents_changed ()
468 if (holding_state ()) {
469 pending_contents_change = true;
471 pending_contents_change = false;
472 ContentsChanged(); /* EMIT SIGNAL */
477 Playlist::notify_layering_changed ()
479 if (holding_state ()) {
480 pending_layering = true;
482 pending_layering = false;
483 LayeringChanged(); /* EMIT SIGNAL */
488 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
490 if (holding_state ()) {
491 pending_removes.insert (r);
492 pending_contents_change = true;
493 pending_length = true;
495 /* this might not be true, but we have to act
496 as though it could be.
498 pending_length = false;
499 LengthChanged (); /* EMIT SIGNAL */
500 pending_contents_change = false;
501 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
502 ContentsChanged (); /* EMIT SIGNAL */
507 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
509 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
511 if (holding_state ()) {
513 pending_range_moves.push_back (move);
517 list< Evoral::RangeMove<framepos_t> > m;
525 Playlist::notify_region_added (boost::shared_ptr<Region> r)
527 /* the length change might not be true, but we have to act
528 as though it could be.
531 if (holding_state()) {
532 pending_adds.insert (r);
533 pending_contents_change = true;
534 pending_length = true;
536 pending_length = false;
537 LengthChanged (); /* EMIT SIGNAL */
538 pending_contents_change = false;
539 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
540 ContentsChanged (); /* EMIT SIGNAL */
545 Playlist::notify_length_changed ()
547 if (holding_state ()) {
548 pending_length = true;
550 pending_length = false;
551 LengthChanged(); /* EMIT SIGNAL */
552 pending_contents_change = false;
553 ContentsChanged (); /* EMIT SIGNAL */
558 Playlist::flush_notifications ()
560 set<boost::shared_ptr<Region> > dependent_checks_needed;
561 set<boost::shared_ptr<Region> >::iterator s;
562 uint32_t regions_changed = false;
563 bool check_length = false;
564 framecnt_t old_length = 0;
572 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
573 regions_changed = true;
574 if (!pending_length) {
575 old_length = _get_maximum_extent ();
580 /* we have no idea what order the regions ended up in pending
581 bounds (it could be based on selection order, for example).
582 so, to preserve layering in the "most recently moved is higher"
583 model, sort them by existing layer, then timestamp them.
586 // RegionSortByLayer cmp;
587 // pending_bounds.sort (cmp);
589 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
590 if (_session.config.get_layer_model() == MoveAddHigher) {
591 timestamp_layer_op (*r);
593 dependent_checks_needed.insert (*r);
596 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
597 remove_dependents (*s);
598 // cerr << _name << " sends RegionRemoved\n";
599 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
602 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
603 // cerr << _name << " sends RegionAdded\n";
604 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
605 dependent_checks_needed.insert (*s);
609 if (old_length != _get_maximum_extent()) {
610 pending_length = true;
611 // cerr << _name << " length has changed\n";
615 if (pending_length || (freeze_length != _get_maximum_extent())) {
616 pending_length = false;
617 // cerr << _name << " sends LengthChanged\n";
618 LengthChanged(); /* EMIT SIGNAL */
621 if (regions_changed || pending_contents_change) {
625 pending_contents_change = false;
626 // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
627 ContentsChanged (); /* EMIT SIGNAL */
628 // cerr << _name << "done contents change @ " << get_microseconds() << endl;
631 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
632 check_dependents (*s, false);
635 if (!pending_range_moves.empty ()) {
636 // cerr << _name << " sends RangesMoved\n";
637 RangesMoved (pending_range_moves);
646 Playlist::clear_pending ()
648 pending_adds.clear ();
649 pending_removes.clear ();
650 pending_bounds.clear ();
651 pending_range_moves.clear ();
652 pending_contents_change = false;
653 pending_length = false;
656 /*************************************************************
658 *************************************************************/
661 Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
663 RegionLock rlock (this);
664 times = fabs (times);
666 int itimes = (int) floor (times);
668 framepos_t pos = position;
670 if (times == 1 && auto_partition){
671 partition(pos, (pos + region->length()), true);
675 add_region_internal (region, pos);
676 pos += region->length();
681 /* note that itimes can be zero if we being asked to just
682 insert a single fraction of the region.
685 for (int i = 0; i < itimes; ++i) {
686 boost::shared_ptr<Region> copy = RegionFactory::create (region);
687 add_region_internal (copy, pos);
688 pos += region->length();
691 framecnt_t length = 0;
693 if (floor (times) != times) {
694 length = (framecnt_t) floor (region->length() * (times - floor (times)));
696 RegionFactory::region_name (name, region->name(), false);
701 plist.add (Properties::start, region->start());
702 plist.add (Properties::length, length);
703 plist.add (Properties::name, name);
704 plist.add (Properties::layer, region->layer());
706 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
707 add_region_internal (sub, pos);
711 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
715 Playlist::set_region_ownership ()
717 RegionLock rl (this);
718 RegionList::iterator i;
719 boost::weak_ptr<Playlist> pl (shared_from_this());
721 for (i = regions.begin(); i != regions.end(); ++i) {
722 (*i)->set_playlist (pl);
727 Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
729 if (region->data_type() != _type){
733 RegionSortByPosition cmp;
735 framecnt_t old_length = 0;
737 if (!holding_state()) {
738 old_length = _get_maximum_extent();
741 if (!first_set_state) {
742 boost::shared_ptr<Playlist> foo (shared_from_this());
743 region->set_playlist (boost::weak_ptr<Playlist>(foo));
746 region->set_position (position, this);
748 timestamp_layer_op (region);
750 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
751 all_regions.insert (region);
753 possibly_splice_unlocked (position, region->length(), region);
755 if (!holding_state ()) {
756 /* layers get assigned from XML state, and are not reset during undo/redo */
760 /* we need to notify the existence of new region before checking dependents. Ick. */
762 notify_region_added (region);
764 if (!holding_state ()) {
766 check_dependents (region, false);
768 if (old_length != _get_maximum_extent()) {
769 notify_length_changed ();
773 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
779 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
781 RegionLock rlock (this);
783 bool old_sp = _splicing;
786 remove_region_internal (old);
787 add_region_internal (newr, pos);
791 possibly_splice_unlocked (pos, old->length() - newr->length());
795 Playlist::remove_region (boost::shared_ptr<Region> region)
797 RegionLock rlock (this);
798 remove_region_internal (region);
802 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
804 RegionList::iterator i;
805 framecnt_t old_length = 0;
808 if (!holding_state()) {
809 old_length = _get_maximum_extent();
814 region->set_playlist (boost::weak_ptr<Playlist>());
817 /* XXX should probably freeze here .... */
819 for (i = regions.begin(); i != regions.end(); ++i) {
822 framepos_t pos = (*i)->position();
823 framecnt_t distance = (*i)->length();
827 possibly_splice_unlocked (pos, -distance);
829 if (!holding_state ()) {
831 remove_dependents (region);
833 if (old_length != _get_maximum_extent()) {
834 notify_length_changed ();
838 notify_region_removed (region);
844 /* XXX and thaw ... */
850 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
852 if (Config->get_use_overlap_equivalency()) {
853 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
854 if ((*i)->overlap_equivalent (other)) {
855 results.push_back ((*i));
859 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
860 if ((*i)->equivalent (other)) {
861 results.push_back ((*i));
868 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
870 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
872 if ((*i) && (*i)->region_list_equivalent (other)) {
873 results.push_back (*i);
879 Playlist::partition (framepos_t start, framepos_t end, bool cut)
883 partition_internal (start, end, cut, thawlist);
885 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
886 (*i)->resume_property_changes ();
891 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
893 RegionList new_regions;
896 RegionLock rlock (this);
898 boost::shared_ptr<Region> region;
899 boost::shared_ptr<Region> current;
901 RegionList::iterator tmp;
903 framepos_t pos1, pos2, pos3, pos4;
907 /* need to work from a copy, because otherwise the regions we add during the process
908 get operated on as well.
911 RegionList copy = regions.rlist();
913 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
920 if (current->first_frame() >= start && current->last_frame() < end) {
923 remove_region_internal (current);
929 /* coverage will return OverlapStart if the start coincides
930 with the end point. we do not partition such a region,
931 so catch this special case.
934 if (current->first_frame() >= end) {
938 if ((overlap = current->coverage (start, end)) == OverlapNone) {
942 pos1 = current->position();
945 pos4 = current->last_frame();
947 if (overlap == OverlapInternal) {
948 /* split: we need 3 new regions, the front, middle and end.
949 cut: we need 2 regions, the front and end.
954 ---------------*************************------------
957 ---------------*****++++++++++++++++====------------
959 ---------------*****----------------====------------
964 /* "middle" ++++++ */
966 RegionFactory::region_name (new_name, current->name(), false);
970 plist.add (Properties::start, current->start() + (pos2 - pos1));
971 plist.add (Properties::length, pos3 - pos2);
972 plist.add (Properties::name, new_name);
973 plist.add (Properties::layer, regions.size());
974 plist.add (Properties::automatic, true);
975 plist.add (Properties::left_of_split, true);
976 plist.add (Properties::right_of_split, true);
978 region = RegionFactory::create (current, plist);
979 add_region_internal (region, start);
980 new_regions.push_back (region);
985 RegionFactory::region_name (new_name, current->name(), false);
989 plist.add (Properties::start, current->start() + (pos3 - pos1));
990 plist.add (Properties::length, pos4 - pos3);
991 plist.add (Properties::name, new_name);
992 plist.add (Properties::layer, regions.size());
993 plist.add (Properties::automatic, true);
994 plist.add (Properties::right_of_split, true);
996 region = RegionFactory::create (current, plist);
998 add_region_internal (region, end);
999 new_regions.push_back (region);
1003 current->suspend_property_changes ();
1004 thawlist.push_back (current);
1005 current->trim_end (pos2, this);
1007 } else if (overlap == OverlapEnd) {
1011 ---------------*************************------------
1014 ---------------**************+++++++++++------------
1016 ---------------**************-----------------------
1023 RegionFactory::region_name (new_name, current->name(), false);
1027 plist.add (Properties::start, current->start() + (pos2 - pos1));
1028 plist.add (Properties::length, pos4 - pos2);
1029 plist.add (Properties::name, new_name);
1030 plist.add (Properties::layer, regions.size());
1031 plist.add (Properties::automatic, true);
1032 plist.add (Properties::left_of_split, true);
1034 region = RegionFactory::create (current, plist);
1036 add_region_internal (region, start);
1037 new_regions.push_back (region);
1042 current->suspend_property_changes ();
1043 thawlist.push_back (current);
1044 current->trim_end (pos2, this);
1046 } else if (overlap == OverlapStart) {
1048 /* split: we need 2 regions: the front and the end.
1049 cut: just trim current to skip the cut area
1054 ---------------*************************------------
1058 ---------------****+++++++++++++++++++++------------
1060 -------------------*********************------------
1066 RegionFactory::region_name (new_name, current->name(), false);
1070 plist.add (Properties::start, current->start());
1071 plist.add (Properties::length, pos3 - pos1);
1072 plist.add (Properties::name, new_name);
1073 plist.add (Properties::layer, regions.size());
1074 plist.add (Properties::automatic, true);
1075 plist.add (Properties::right_of_split, true);
1077 region = RegionFactory::create (current, plist);
1079 add_region_internal (region, pos1);
1080 new_regions.push_back (region);
1085 current->suspend_property_changes ();
1086 thawlist.push_back (current);
1087 current->trim_front (pos3, this);
1088 } else if (overlap == OverlapExternal) {
1090 /* split: no split required.
1091 cut: remove the region.
1096 ---------------*************************------------
1100 ---------------*************************------------
1102 ----------------------------------------------------
1107 remove_region_internal (current);
1110 new_regions.push_back (current);
1114 in_partition = false;
1117 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1118 check_dependents (*i, false);
1122 boost::shared_ptr<Playlist>
1123 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1125 boost::shared_ptr<Playlist> ret;
1126 boost::shared_ptr<Playlist> pl;
1129 if (ranges.empty()) {
1130 return boost::shared_ptr<Playlist>();
1133 start = ranges.front().start;
1135 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1137 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1139 if (i == ranges.begin()) {
1143 /* paste the next section into the nascent playlist,
1144 offset to reflect the start of the first range we
1148 ret->paste (pl, (*i).start - start, 1.0f);
1155 boost::shared_ptr<Playlist>
1156 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1158 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1159 return cut_copy (pmf, ranges, result_is_hidden);
1162 boost::shared_ptr<Playlist>
1163 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1165 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1166 return cut_copy (pmf, ranges, result_is_hidden);
1169 boost::shared_ptr<Playlist>
1170 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1172 boost::shared_ptr<Playlist> the_copy;
1173 RegionList thawlist;
1176 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1177 string new_name = _name;
1181 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1182 return boost::shared_ptr<Playlist>();
1185 partition_internal (start, start+cnt-1, true, thawlist);
1187 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1188 (*i)->resume_property_changes();
1194 boost::shared_ptr<Playlist>
1195 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1199 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1200 string new_name = _name;
1204 cnt = min (_get_maximum_extent() - start, cnt);
1205 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1209 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1211 times = fabs (times);
1214 RegionLock rl1 (this);
1215 RegionLock rl2 (other.get());
1217 framecnt_t old_length = _get_maximum_extent();
1219 int itimes = (int) floor (times);
1220 framepos_t pos = position;
1221 framecnt_t shift = other->_get_maximum_extent();
1222 layer_t top_layer = regions.size();
1225 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1226 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1228 /* put these new regions on top of all existing ones, but preserve
1229 the ordering they had in the original playlist.
1232 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1233 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1239 /* XXX shall we handle fractional cases at some point? */
1241 if (old_length != _get_maximum_extent()) {
1242 notify_length_changed ();
1253 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1255 times = fabs (times);
1257 RegionLock rl (this);
1258 int itimes = (int) floor (times);
1259 framepos_t pos = position;
1262 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1263 add_region_internal (copy, pos);
1264 pos += region->length();
1267 if (floor (times) != times) {
1268 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1270 RegionFactory::region_name (name, region->name(), false);
1275 plist.add (Properties::start, region->start());
1276 plist.add (Properties::length, length);
1277 plist.add (Properties::name, name);
1279 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1280 add_region_internal (sub, pos);
1286 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1288 RegionLock rlock (this);
1289 RegionList copy (regions.rlist());
1292 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1294 if ((*r)->last_frame() < at) {
1299 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1300 /* intersected region */
1301 if (!move_intersected) {
1306 /* do not move regions glued to music time - that
1307 has to be done separately.
1310 if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
1311 fixup.push_back (*r);
1315 (*r)->set_position ((*r)->position() + distance, this);
1318 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1319 (*r)->recompute_position_from_lock_style ();
1324 Playlist::split (framepos_t at)
1326 RegionLock rlock (this);
1327 RegionList copy (regions.rlist());
1329 /* use a copy since this operation can modify the region list
1332 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1333 _split_region (*r, at);
1338 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1340 RegionLock rl (this);
1341 _split_region (region, playlist_position);
1345 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1347 if (!region->covers (playlist_position)) {
1351 if (region->position() == playlist_position ||
1352 region->last_frame() == playlist_position) {
1356 boost::shared_ptr<Region> left;
1357 boost::shared_ptr<Region> right;
1358 frameoffset_t before;
1359 frameoffset_t after;
1363 /* split doesn't change anything about length, so don't try to splice */
1365 bool old_sp = _splicing;
1368 before = playlist_position - region->position();
1369 after = region->length() - before;
1371 RegionFactory::region_name (before_name, region->name(), false);
1376 plist.add (Properties::start, region->start());
1377 plist.add (Properties::length, before);
1378 plist.add (Properties::name, before_name);
1379 plist.add (Properties::left_of_split, true);
1381 left = RegionFactory::create (region, plist);
1384 RegionFactory::region_name (after_name, region->name(), false);
1389 plist.add (Properties::start, region->start() + before);
1390 plist.add (Properties::length, after);
1391 plist.add (Properties::name, after_name);
1392 plist.add (Properties::right_of_split, true);
1394 right = RegionFactory::create (region, plist);
1397 add_region_internal (left, region->position());
1398 add_region_internal (right, region->position() + before);
1400 uint64_t orig_layer_op = region->last_layer_op();
1401 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1402 if ((*i)->last_layer_op() > orig_layer_op) {
1403 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1407 left->set_last_layer_op ( orig_layer_op );
1408 right->set_last_layer_op ( orig_layer_op + 1);
1412 finalize_split_region (region, left, right);
1414 remove_region_internal (region);
1420 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1422 if (_splicing || in_set_state) {
1423 /* don't respond to splicing moves or state setting */
1427 if (_edit_mode == Splice) {
1428 splice_locked (at, distance, exclude);
1433 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1435 if (_splicing || in_set_state) {
1436 /* don't respond to splicing moves or state setting */
1440 if (_edit_mode == Splice) {
1441 splice_unlocked (at, distance, exclude);
1446 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1449 RegionLock rl (this);
1450 core_splice (at, distance, exclude);
1455 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1457 core_splice (at, distance, exclude);
1461 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1465 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1467 if (exclude && (*i) == exclude) {
1471 if ((*i)->position() >= at) {
1472 framepos_t new_pos = (*i)->position() + distance;
1475 } else if (new_pos >= max_frames - (*i)->length()) {
1476 new_pos = max_frames - (*i)->length();
1479 (*i)->set_position (new_pos, this);
1485 notify_length_changed ();
1489 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1491 if (in_set_state || _splicing || _nudging || _shuffling) {
1495 if (what_changed.contains (Properties::position)) {
1497 /* remove it from the list then add it back in
1498 the right place again.
1501 RegionSortByPosition cmp;
1503 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1505 if (i == regions.end()) {
1506 /* the region bounds are being modified but its not currently
1507 in the region list. we will use its bounds correctly when/if
1514 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1517 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1519 frameoffset_t delta = 0;
1521 if (what_changed.contains (Properties::position)) {
1522 delta = region->position() - region->last_position();
1525 if (what_changed.contains (Properties::length)) {
1526 delta += region->length() - region->last_length();
1530 possibly_splice (region->last_position() + region->last_length(), delta, region);
1533 if (holding_state ()) {
1534 pending_bounds.push_back (region);
1536 if (_session.config.get_layer_model() == MoveAddHigher) {
1537 /* it moved or changed length, so change the timestamp */
1538 timestamp_layer_op (region);
1541 notify_length_changed ();
1543 check_dependents (region, false);
1549 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1551 boost::shared_ptr<Region> region (weak_region.lock());
1557 /* this makes a virtual call to the right kind of playlist ... */
1559 region_changed (what_changed, region);
1563 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1565 PropertyChange our_interests;
1566 PropertyChange bounds;
1567 PropertyChange pos_and_length;
1570 if (in_set_state || in_flush) {
1574 our_interests.add (Properties::muted);
1575 our_interests.add (Properties::layer);
1576 our_interests.add (Properties::opaque);
1578 bounds.add (Properties::start);
1579 bounds.add (Properties::position);
1580 bounds.add (Properties::length);
1582 pos_and_length.add (Properties::position);
1583 pos_and_length.add (Properties::length);
1585 if (what_changed.contains (bounds)) {
1586 region_bounds_changed (what_changed, region);
1587 save = !(_splicing || _nudging);
1590 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1591 check_dependents (region, false);
1594 if (what_changed.contains (Properties::position)) {
1595 notify_region_moved (region);
1599 /* don't notify about layer changes, since we are the only object that can initiate
1600 them, and we notify in ::relayer()
1603 if (what_changed.contains (our_interests)) {
1611 Playlist::drop_regions ()
1613 RegionLock rl (this);
1615 all_regions.clear ();
1619 Playlist::clear (bool with_signals)
1622 RegionLock rl (this);
1624 region_state_changed_connections.drop_connections ();
1626 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1627 pending_removes.insert (*i);
1632 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1633 remove_dependents (*s);
1639 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1640 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1643 pending_removes.clear ();
1644 pending_length = false;
1646 pending_contents_change = false;
1652 /***********************************************************************
1654 **********************************************************************/
1656 Playlist::RegionList *
1657 Playlist::regions_at (framepos_t frame)
1660 RegionLock rlock (this);
1661 return find_regions_at (frame);
1664 boost::shared_ptr<Region>
1665 Playlist::top_region_at (framepos_t frame)
1668 RegionLock rlock (this);
1669 RegionList *rlist = find_regions_at (frame);
1670 boost::shared_ptr<Region> region;
1672 if (rlist->size()) {
1673 RegionSortByLayer cmp;
1675 region = rlist->back();
1682 boost::shared_ptr<Region>
1683 Playlist::top_unmuted_region_at (framepos_t frame)
1686 RegionLock rlock (this);
1687 RegionList *rlist = find_regions_at (frame);
1689 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1691 RegionList::iterator tmp = i;
1694 if ((*i)->muted()) {
1701 boost::shared_ptr<Region> region;
1703 if (rlist->size()) {
1704 RegionSortByLayer cmp;
1706 region = rlist->back();
1713 Playlist::RegionList*
1714 Playlist::regions_to_read (framepos_t start, framepos_t end)
1716 /* Caller must hold lock */
1718 RegionList covering;
1719 set<framepos_t> to_check;
1720 set<boost::shared_ptr<Region> > unique;
1722 to_check.insert (start);
1723 to_check.insert (end);
1725 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1727 /* find all/any regions that span start+end */
1729 switch ((*i)->coverage (start, end)) {
1733 case OverlapInternal:
1734 covering.push_back (*i);
1738 to_check.insert ((*i)->position());
1739 covering.push_back (*i);
1743 to_check.insert ((*i)->last_frame());
1744 covering.push_back (*i);
1747 case OverlapExternal:
1748 covering.push_back (*i);
1749 to_check.insert ((*i)->position());
1750 to_check.insert ((*i)->last_frame());
1754 /* don't go too far */
1756 if ((*i)->position() > end) {
1761 RegionList* rlist = new RegionList;
1763 /* find all the regions that cover each position .... */
1765 if (covering.size() == 1) {
1767 rlist->push_back (covering.front());
1772 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1776 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1778 if ((*x)->covers (*t)) {
1779 here.push_back (*x);
1783 RegionSortByLayer cmp;
1786 /* ... and get the top/transparent regions at "here" */
1788 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1792 if ((*c)->opaque()) {
1794 /* the other regions at this position are hidden by this one */
1801 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1802 rlist->push_back (*s);
1805 if (rlist->size() > 1) {
1806 /* now sort by time order */
1808 RegionSortByPosition cmp;
1816 Playlist::RegionList *
1817 Playlist::find_regions_at (framepos_t frame)
1819 /* Caller must hold lock */
1821 RegionList *rlist = new RegionList;
1823 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1824 if ((*i)->covers (frame)) {
1825 rlist->push_back (*i);
1832 Playlist::RegionList *
1833 Playlist::regions_touched (framepos_t start, framepos_t end)
1835 RegionLock rlock (this);
1836 RegionList *rlist = new RegionList;
1838 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1839 if ((*i)->coverage (start, end) != OverlapNone) {
1840 rlist->push_back (*i);
1848 Playlist::find_next_transient (framepos_t from, int dir)
1850 RegionLock rlock (this);
1851 AnalysisFeatureList points;
1852 AnalysisFeatureList these_points;
1854 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1856 if ((*i)->last_frame() < from) {
1860 if ((*i)->first_frame() > from) {
1865 (*i)->get_transients (these_points);
1867 /* add first frame, just, err, because */
1869 these_points.push_back ((*i)->first_frame());
1871 points.insert (points.end(), these_points.begin(), these_points.end());
1872 these_points.clear ();
1875 if (points.empty()) {
1879 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1880 bool reached = false;
1883 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1888 if (reached && (*x) > from) {
1893 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1898 if (reached && (*x) < from) {
1907 boost::shared_ptr<Region>
1908 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1910 RegionLock rlock (this);
1911 boost::shared_ptr<Region> ret;
1912 framepos_t closest = max_frames;
1914 bool end_iter = false;
1916 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1920 frameoffset_t distance;
1921 boost::shared_ptr<Region> r = (*i);
1926 pos = r->first_frame ();
1929 pos = r->last_frame ();
1932 pos = r->sync_position ();
1933 // r->adjust_to_sync (r->first_frame());
1938 case 1: /* forwards */
1941 if ((distance = pos - frame) < closest) {
1950 default: /* backwards */
1953 if ((distance = frame - pos) < closest) {
1970 Playlist::find_next_region_boundary (framepos_t frame, int dir)
1972 RegionLock rlock (this);
1974 framepos_t closest = max_frames;
1975 framepos_t ret = -1;
1979 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1981 boost::shared_ptr<Region> r = (*i);
1982 frameoffset_t distance;
1984 if (r->first_frame() > frame) {
1986 distance = r->first_frame() - frame;
1988 if (distance < closest) {
1989 ret = r->first_frame();
1994 if (r->last_frame () > frame) {
1996 distance = r->last_frame () - frame;
1998 if (distance < closest) {
1999 ret = r->last_frame ();
2007 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2009 boost::shared_ptr<Region> r = (*i);
2010 frameoffset_t distance;
2012 if (r->last_frame() < frame) {
2014 distance = frame - r->last_frame();
2016 if (distance < closest) {
2017 ret = r->last_frame();
2022 if (r->first_frame() < frame) {
2024 distance = frame - r->first_frame();
2026 if (distance < closest) {
2027 ret = r->first_frame();
2037 /***********************************************************************/
2043 Playlist::mark_session_dirty ()
2045 if (!in_set_state && !holding_state ()) {
2046 _session.set_dirty();
2051 Playlist::set_property (const PropertyBase& prop)
2053 if (prop == Properties::regions.property_id) {
2054 const RegionListProperty::ChangeRecord& change (dynamic_cast<const RegionListProperty*>(&prop)->change());
2055 regions.update (change);
2056 return (!change.added.empty() && !change.removed.empty());
2062 Playlist::rdiff (vector<StatefulDiffCommand*>& cmds) const
2064 RegionLock rlock (const_cast<Playlist *> (this));
2066 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2067 if ((*i)->changed ()) {
2068 StatefulDiffCommand* sdc = new StatefulDiffCommand (*i);
2069 cmds.push_back (sdc);
2075 Playlist::clear_owned_history ()
2077 RegionLock rlock (this);
2079 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2080 (*i)->clear_history ();
2085 Playlist::update (const RegionListProperty::ChangeRecord& change)
2087 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2088 name(), change.added.size(), change.removed.size()));
2091 /* add the added regions */
2092 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2093 add_region ((*i), (*i)->position());
2095 /* remove the removed regions */
2096 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2104 Playlist::property_factory (const XMLNode& history_node) const
2106 const XMLNodeList& children (history_node.children());
2107 PropertyList* prop_list = 0;
2109 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2111 if ((*i)->name() == capitalize (regions.property_name())) {
2113 RegionListProperty* rlp = new RegionListProperty (*const_cast<Playlist*> (this));
2115 if (rlp->load_history_state (**i)) {
2117 prop_list = new PropertyList();
2119 prop_list->add (rlp);
2130 Playlist::set_state (const XMLNode& node, int version)
2134 XMLNodeConstIterator niter;
2135 XMLPropertyList plist;
2136 XMLPropertyConstIterator piter;
2138 boost::shared_ptr<Region> region;
2143 if (node.name() != "Playlist") {
2150 plist = node.properties();
2152 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2156 if (prop->name() == X_("name")) {
2157 _name = prop->value();
2159 } else if (prop->name() == X_("id")) {
2160 _id = prop->value();
2161 } else if (prop->name() == X_("orig_diskstream_id")) {
2162 _orig_diskstream_id = prop->value ();
2163 } else if (prop->name() == X_("frozen")) {
2164 _frozen = string_is_affirmative (prop->value());
2170 nlist = node.children();
2172 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2176 if (child->name() == "Region") {
2178 if ((prop = child->property ("id")) == 0) {
2179 error << _("region state node has no ID, ignored") << endmsg;
2183 ID id = prop->value ();
2185 if ((region = region_by_id (id))) {
2187 region->suspend_property_changes ();
2189 if (region->set_state (*child, version)) {
2190 region->resume_property_changes ();
2194 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2195 region->suspend_property_changes ();
2197 error << _("Playlist: cannot create region from XML") << endmsg;
2201 add_region (region, region->position(), 1.0);
2203 // So that layer_op ordering doesn't get screwed up
2204 region->set_last_layer_op( region->layer());
2205 region->resume_property_changes ();
2209 /* update dependents, which was not done during add_region_internal
2210 due to in_set_state being true
2213 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2214 check_dependents (*r, false);
2218 notify_contents_changed ();
2221 first_set_state = false;
2226 Playlist::get_state()
2228 return state (true);
2232 Playlist::get_template()
2234 return state (false);
2237 /** @param full_state true to include regions in the returned state, otherwise false.
2240 Playlist::state (bool full_state)
2242 XMLNode *node = new XMLNode (X_("Playlist"));
2245 node->add_property (X_("id"), id().to_s());
2246 node->add_property (X_("name"), _name);
2247 node->add_property (X_("type"), _type.to_string());
2249 _orig_diskstream_id.print (buf, sizeof (buf));
2250 node->add_property (X_("orig_diskstream_id"), buf);
2251 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2254 RegionLock rlock (this, false);
2255 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2256 node->add_child_nocopy ((*i)->get_state());
2261 node->add_child_copy (*_extra_xml);
2268 Playlist::empty() const
2270 RegionLock rlock (const_cast<Playlist *>(this), false);
2271 return regions.empty();
2275 Playlist::n_regions() const
2277 RegionLock rlock (const_cast<Playlist *>(this), false);
2278 return regions.size();
2282 Playlist::get_maximum_extent () const
2284 RegionLock rlock (const_cast<Playlist *>(this), false);
2285 return _get_maximum_extent ();
2289 Playlist::_get_maximum_extent () const
2291 RegionList::const_iterator i;
2292 framecnt_t max_extent = 0;
2295 for (i = regions.begin(); i != regions.end(); ++i) {
2296 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
2305 Playlist::bump_name (string name, Session &session)
2307 string newname = name;
2310 newname = bump_name_once (newname);
2311 } while (session.playlists->by_name (newname)!=NULL);
2318 Playlist::top_layer() const
2320 RegionLock rlock (const_cast<Playlist *> (this));
2323 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2324 top = max (top, (*i)->layer());
2330 Playlist::set_edit_mode (EditMode mode)
2335 /********************
2337 ********************/
2340 Playlist::relayer ()
2342 /* never compute layers when changing state for undo/redo or setting from XML*/
2344 if (in_update || in_set_state) {
2348 bool changed = false;
2350 /* Build up a new list of regions on each layer, stored in a set of lists
2351 each of which represent some period of time on some layer. The idea
2352 is to avoid having to search the entire region list to establish whether
2353 each region overlaps another */
2355 /* how many pieces to divide this playlist's time up into */
2356 int const divisions = 512;
2358 /* find the start and end positions of the regions on this playlist */
2359 framepos_t start = UINT_MAX;
2361 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2362 start = min (start, (*i)->position());
2363 end = max (end, (*i)->position() + (*i)->length());
2366 /* hence the size of each time division */
2367 double const division_size = (end - start) / double (divisions);
2369 vector<vector<RegionList> > layers;
2370 layers.push_back (vector<RegionList> (divisions));
2372 /* we want to go through regions from desired lowest to desired highest layer,
2373 which depends on the layer model
2376 RegionList copy = regions.rlist();
2378 /* sort according to the model and the layering mode that we're in */
2380 if (_explicit_relayering) {
2382 copy.sort (RegionSortByLayerWithPending ());
2384 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2386 copy.sort (RegionSortByLastLayerOp ());
2391 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2393 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2394 (*i)->set_pending_explicit_relayer (false);
2396 /* find the time divisions that this region covers */
2397 int const start_division = floor ( ((*i)->position() - start) / division_size);
2398 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2399 if (end_division == divisions) {
2403 assert (end_division < divisions);
2405 /* find the lowest layer that this region can go on */
2406 size_t j = layers.size();
2408 /* try layer j - 1; it can go on if it overlaps no other region
2409 that is already on that layer
2412 bool overlap = false;
2413 for (int k = start_division; k <= end_division; ++k) {
2414 RegionList::iterator l = layers[j-1][k].begin ();
2415 while (l != layers[j-1][k].end()) {
2416 if ((*l)->overlap_equivalent (*i)) {
2429 /* overlap, so we must use layer j */
2436 if (j == layers.size()) {
2437 /* we need a new layer for this region */
2438 layers.push_back (vector<RegionList> (divisions));
2441 /* put a reference to this region in each of the divisions that it exists in */
2442 for (int k = start_division; k <= end_division; ++k) {
2443 layers[j][k].push_back (*i);
2446 if ((*i)->layer() != j) {
2450 (*i)->set_layer (j);
2454 notify_layering_changed ();
2458 /* XXX these layer functions are all deprecated */
2461 Playlist::raise_region (boost::shared_ptr<Region> region)
2463 uint32_t rsz = regions.size();
2464 layer_t target = region->layer() + 1U;
2466 if (target >= rsz) {
2467 /* its already at the effective top */
2471 move_region_to_layer (target, region, 1);
2475 Playlist::lower_region (boost::shared_ptr<Region> region)
2477 if (region->layer() == 0) {
2478 /* its already at the bottom */
2482 layer_t target = region->layer() - 1U;
2484 move_region_to_layer (target, region, -1);
2488 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2490 /* does nothing useful if layering mode is later=higher */
2491 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2492 (_session.config.get_layer_model() == AddHigher)) {
2493 timestamp_layer_op (region);
2499 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2501 /* does nothing useful if layering mode is later=higher */
2502 if ((_session.config.get_layer_model() == MoveAddHigher) ||
2503 (_session.config.get_layer_model() == AddHigher)) {
2504 region->set_last_layer_op (0);
2510 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2512 RegionList::iterator i;
2513 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2514 list<LayerInfo> layerinfo;
2517 RegionLock rlock (const_cast<Playlist *> (this));
2519 for (i = regions.begin(); i != regions.end(); ++i) {
2529 /* region is moving up, move all regions on intermediate layers
2533 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2534 dest = (*i)->layer() - 1;
2541 /* region is moving down, move all regions on intermediate layers
2545 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2546 dest = (*i)->layer() + 1;
2556 newpair.second = dest;
2558 layerinfo.push_back (newpair);
2562 /* now reset the layers without holding the region lock */
2564 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2565 x->first->set_layer (x->second);
2568 region->set_layer (target_layer);
2571 /* now check all dependents */
2573 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2574 check_dependents (x->first, false);
2577 check_dependents (region, false);
2584 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2586 RegionList::iterator i;
2592 RegionLock rlock (const_cast<Playlist *> (this));
2594 for (i = regions.begin(); i != regions.end(); ++i) {
2596 if ((*i)->position() >= start) {
2602 if ((*i)->last_frame() > max_frames - distance) {
2603 new_pos = max_frames - (*i)->length();
2605 new_pos = (*i)->position() + distance;
2610 if ((*i)->position() > distance) {
2611 new_pos = (*i)->position() - distance;
2617 (*i)->set_position (new_pos, this);
2625 notify_length_changed ();
2630 boost::shared_ptr<Region>
2631 Playlist::find_region (const ID& id) const
2633 RegionLock rlock (const_cast<Playlist*> (this));
2635 /* searches all regions currently in use by the playlist */
2637 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2638 if ((*i)->id() == id) {
2643 return boost::shared_ptr<Region> ();
2646 boost::shared_ptr<Region>
2647 Playlist::region_by_id (const ID& id)
2649 /* searches all regions ever added to this playlist */
2651 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2652 if ((*i)->id() == id) {
2656 return boost::shared_ptr<Region> ();
2660 Playlist::dump () const
2662 boost::shared_ptr<Region> r;
2664 cerr << "Playlist \"" << _name << "\" " << endl
2665 << regions.size() << " regions "
2668 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2670 cerr << " " << r->name() << " ["
2671 << r->start() << "+" << r->length()
2681 Playlist::set_frozen (bool yn)
2687 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2689 // struct timeval tv;
2690 // gettimeofday (&tv, 0);
2691 region->set_last_layer_op (++layer_op_counter);
2696 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2700 if (region->locked()) {
2707 RegionLock rlock (const_cast<Playlist*> (this));
2712 RegionList::iterator next;
2714 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2715 if ((*i) == region) {
2719 if (next != regions.end()) {
2721 if ((*next)->locked()) {
2727 if ((*next)->position() != region->last_frame() + 1) {
2728 /* they didn't used to touch, so after shuffle,
2729 just have them swap positions.
2731 new_pos = (*next)->position();
2733 /* they used to touch, so after shuffle,
2734 make sure they still do. put the earlier
2735 region where the later one will end after
2738 new_pos = region->position() + (*next)->length();
2741 (*next)->set_position (region->position(), this);
2742 region->set_position (new_pos, this);
2744 /* avoid a full sort */
2746 regions.erase (i); // removes the region from the list */
2748 regions.insert (next, region); // adds it back after next
2757 RegionList::iterator prev = regions.end();
2759 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2760 if ((*i) == region) {
2762 if (prev != regions.end()) {
2764 if ((*prev)->locked()) {
2769 if (region->position() != (*prev)->last_frame() + 1) {
2770 /* they didn't used to touch, so after shuffle,
2771 just have them swap positions.
2773 new_pos = region->position();
2775 /* they used to touch, so after shuffle,
2776 make sure they still do. put the earlier
2777 one where the later one will end after
2779 new_pos = (*prev)->position() + region->length();
2782 region->set_position ((*prev)->position(), this);
2783 (*prev)->set_position (new_pos, this);
2785 /* avoid a full sort */
2787 regions.erase (i); // remove region
2788 regions.insert (prev, region); // insert region before prev
2804 check_dependents (region, false);
2806 notify_contents_changed();
2812 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2814 RegionLock rlock (const_cast<Playlist*> (this));
2816 if (regions.size() > 1) {
2824 Playlist::update_after_tempo_map_change ()
2826 RegionLock rlock (const_cast<Playlist*> (this));
2827 RegionList copy (regions.rlist());
2831 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2832 (*i)->update_position_after_tempo_map_change ();
2839 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2841 RegionLock rl (this, false);
2842 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2848 Playlist::set_explicit_relayering (bool e)
2850 if (e == false && _explicit_relayering == true) {
2852 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2853 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2854 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2855 at this point would keep regions on the same layers.
2857 From then on in, it's just you and your towel.
2860 RegionLock rl (this);
2861 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2862 (*i)->set_last_layer_op ((*i)->layer ());
2866 _explicit_relayering = e;
2871 Playlist::has_region_at (framepos_t const p) const
2873 RegionLock (const_cast<Playlist *> (this));
2875 RegionList::const_iterator i = regions.begin ();
2876 while (i != regions.end() && !(*i)->covers (p)) {
2880 return (i != regions.end());