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"
35 #include "ardour/debug.h"
36 #include "ardour/playlist.h"
37 #include "ardour/session.h"
38 #include "ardour/region.h"
39 #include "ardour/region_factory.h"
40 #include "ardour/playlist_factory.h"
41 #include "ardour/transient_detector.h"
42 #include "ardour/session_playlists.h"
47 using namespace ARDOUR;
51 namespace Properties {
52 PBD::PropertyDescriptor<bool> regions;
56 struct ShowMeTheList {
57 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
59 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
61 boost::shared_ptr<Playlist> playlist;
65 struct RegionSortByLayer {
66 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
67 return a->layer() < b->layer();
71 struct RegionSortByLayerWithPending {
72 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
74 double p = a->layer ();
75 if (a->pending_explicit_relayer()) {
79 double q = b->layer ();
80 if (b->pending_explicit_relayer()) {
88 struct RegionSortByPosition {
89 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
90 return a->position() < b->position();
94 struct RegionSortByLastLayerOp {
95 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
96 return a->last_layer_op() < b->last_layer_op();
101 Playlist::make_property_quarks ()
103 Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
104 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n", Properties::regions.property_id));
107 RegionListProperty::RegionListProperty (Playlist& pl)
108 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
114 RegionListProperty::RegionListProperty (RegionListProperty const & p)
115 : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
116 , _playlist (p._playlist)
122 RegionListProperty::clone () const
124 return new RegionListProperty (*this);
128 RegionListProperty::create () const
130 return new RegionListProperty (_playlist);
134 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
136 /* All regions (even those which are deleted) have their state saved by other
137 code, so we can just store ID here.
140 node.add_property ("id", region->id().to_s ());
143 boost::shared_ptr<Region>
144 RegionListProperty::get_content_from_xml (XMLNode const & node) const
146 XMLProperty const * prop = node.property ("id");
149 PBD::ID id (prop->value ());
151 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
154 ret = RegionFactory::region_by_id (id);
160 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
161 : SessionObject(sess, nom)
166 first_set_state = false;
172 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
173 : SessionObject(sess, "unnamed playlist")
179 const XMLProperty* prop = node.property("type");
180 assert(!prop || DataType(prop->value()) == _type);
184 _name = "unnamed"; /* reset by set_state */
187 /* set state called by derived class */
190 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
191 : SessionObject(other->_session, namestr)
193 , _type(other->_type)
194 , _orig_diskstream_id (other->_orig_diskstream_id)
199 other->copy_regions (tmp);
203 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
204 add_region_internal( (*x), (*x)->position());
209 _splicing = other->_splicing;
210 _nudging = other->_nudging;
211 _edit_mode = other->_edit_mode;
214 first_set_state = false;
216 in_partition = false;
218 _read_data_count = 0;
219 _frozen = other->_frozen;
221 layer_op_counter = other->layer_op_counter;
222 freeze_length = other->freeze_length;
225 Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
226 : SessionObject(other->_session, str)
228 , _type(other->_type)
229 , _orig_diskstream_id (other->_orig_diskstream_id)
231 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
233 framepos_t end = start + cnt - 1;
239 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
241 boost::shared_ptr<Region> region;
242 boost::shared_ptr<Region> new_region;
243 frameoffset_t offset = 0;
244 framepos_t position = 0;
251 overlap = region->coverage (start, end);
257 case OverlapInternal:
258 offset = start - region->position();
265 position = region->position() - start;
266 len = end - region->position();
270 offset = start - region->position();
272 len = region->length() - offset;
275 case OverlapExternal:
277 position = region->position() - start;
278 len = region->length();
282 RegionFactory::region_name (new_name, region->name(), false);
286 plist.add (Properties::start, region->start() + offset);
287 plist.add (Properties::length, len);
288 plist.add (Properties::name, new_name);
289 plist.add (Properties::layer, region->layer());
291 new_region = RegionFactory::RegionFactory::create (region, plist);
293 add_region_internal (new_region, position);
297 first_set_state = false;
299 /* this constructor does NOT notify others (session) */
306 InUse (true); /* EMIT SIGNAL */
317 InUse (false); /* EMIT SIGNAL */
322 Playlist::copy_regions (RegionList& newlist) const
324 RegionLock rlock (const_cast<Playlist *> (this));
326 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
327 newlist.push_back (RegionFactory::RegionFactory::create (*i));
332 Playlist::init (bool hide)
334 add_property (regions);
335 _xml_node_name = X_("Playlist");
337 g_atomic_int_set (&block_notifications, 0);
338 g_atomic_int_set (&ignore_state_changes, 0);
339 pending_contents_change = false;
340 pending_length = false;
341 pending_layering = false;
342 first_set_state = true;
350 _edit_mode = Config->get_edit_mode();
352 in_partition = false;
354 _read_data_count = 0;
356 layer_op_counter = 0;
358 _explicit_relayering = false;
360 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
361 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
363 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
366 Playlist::~Playlist ()
368 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
371 RegionLock rl (this);
373 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
374 (*i)->set_playlist (boost::shared_ptr<Playlist>());
378 /* GoingAway must be emitted by derived classes */
382 Playlist::_set_sort_id ()
385 Playlists are given names like <track name>.<id>
386 or <track name>.<edit group name>.<id> where id
387 is an integer. We extract the id and sort by that.
390 size_t dot_position = _name.val().find_last_of(".");
392 if (dot_position == string::npos) {
395 string t = _name.val().substr(dot_position + 1);
398 _sort_id = boost::lexical_cast<int>(t);
401 catch (boost::bad_lexical_cast e) {
408 Playlist::set_name (const string& str)
410 /* in a typical situation, a playlist is being used
411 by one diskstream and also is referenced by the
412 Session. if there are more references than that,
413 then don't change the name.
420 bool ret = SessionObject::set_name(str);
427 /***********************************************************************
428 CHANGE NOTIFICATION HANDLING
430 Notifications must be delayed till the region_lock is released. This
431 is necessary because handlers for the signals may need to acquire
432 the lock (e.g. to read from the playlist).
433 ***********************************************************************/
436 Playlist::begin_undo ()
443 Playlist::end_undo ()
452 delay_notifications ();
453 g_atomic_int_inc (&ignore_state_changes);
456 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
458 Playlist::thaw (bool from_undo)
460 g_atomic_int_dec_and_test (&ignore_state_changes);
461 release_notifications (from_undo);
466 Playlist::delay_notifications ()
468 g_atomic_int_inc (&block_notifications);
469 freeze_length = _get_extent().second;
472 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
474 Playlist::release_notifications (bool from_undo)
476 if (g_atomic_int_dec_and_test (&block_notifications)) {
477 flush_notifications (from_undo);
483 Playlist::notify_contents_changed ()
485 if (holding_state ()) {
486 pending_contents_change = true;
488 pending_contents_change = false;
489 ContentsChanged(); /* EMIT SIGNAL */
494 Playlist::notify_layering_changed ()
496 if (holding_state ()) {
497 pending_layering = true;
499 pending_layering = false;
500 LayeringChanged(); /* EMIT SIGNAL */
505 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
507 if (holding_state ()) {
508 pending_removes.insert (r);
509 pending_contents_change = true;
510 pending_length = true;
512 /* this might not be true, but we have to act
513 as though it could be.
515 pending_length = false;
516 LengthChanged (); /* EMIT SIGNAL */
517 pending_contents_change = false;
518 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
519 ContentsChanged (); /* EMIT SIGNAL */
524 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
526 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
528 if (holding_state ()) {
530 pending_range_moves.push_back (move);
534 list< Evoral::RangeMove<framepos_t> > m;
536 RangesMoved (m, false);
542 Playlist::notify_region_added (boost::shared_ptr<Region> r)
544 /* the length change might not be true, but we have to act
545 as though it could be.
548 if (holding_state()) {
549 pending_adds.insert (r);
550 pending_contents_change = true;
551 pending_length = true;
554 pending_length = false;
555 LengthChanged (); /* EMIT SIGNAL */
556 pending_contents_change = false;
557 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
558 ContentsChanged (); /* EMIT SIGNAL */
563 Playlist::notify_length_changed ()
565 if (holding_state ()) {
566 pending_length = true;
568 pending_length = false;
569 LengthChanged(); /* EMIT SIGNAL */
570 pending_contents_change = false;
571 ContentsChanged (); /* EMIT SIGNAL */
575 /** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
577 Playlist::flush_notifications (bool from_undo)
579 set<boost::shared_ptr<Region> > dependent_checks_needed;
580 set<boost::shared_ptr<Region> >::iterator s;
581 uint32_t regions_changed = false;
582 bool check_length = false;
583 framecnt_t old_length = 0;
591 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
592 regions_changed = true;
593 if (!pending_length) {
594 old_length = _get_extent ().second;
599 /* we have no idea what order the regions ended up in pending
600 bounds (it could be based on selection order, for example).
601 so, to preserve layering in the "most recently moved is higher"
602 model, sort them by existing layer, then timestamp them.
605 // RegionSortByLayer cmp;
606 // pending_bounds.sort (cmp);
608 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
609 if (_session.config.get_layer_model() == MoveAddHigher) {
610 timestamp_layer_op (*r);
612 dependent_checks_needed.insert (*r);
615 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
616 remove_dependents (*s);
617 // cerr << _name << " sends RegionRemoved\n";
618 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
621 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
622 // cerr << _name << " sends RegionAdded\n";
623 /* don't emit RegionAdded signal until relayering is done,
624 so that the region is fully setup by the time
625 anyone hear's that its been added
627 dependent_checks_needed.insert (*s);
631 if (old_length != _get_extent().second) {
632 pending_length = true;
633 // cerr << _name << " length has changed\n";
637 if (pending_length || (freeze_length != _get_extent().second)) {
638 pending_length = false;
639 // cerr << _name << " sends LengthChanged\n";
640 LengthChanged(); /* EMIT SIGNAL */
643 if (regions_changed || pending_contents_change) {
647 pending_contents_change = false;
648 // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
649 ContentsChanged (); /* EMIT SIGNAL */
650 // cerr << _name << "done contents change @ " << get_microseconds() << endl;
653 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
654 (*s)->clear_changes ();
655 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
658 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
659 check_dependents (*s, false);
662 if (!pending_range_moves.empty ()) {
663 RangesMoved (pending_range_moves, from_undo);
672 Playlist::clear_pending ()
674 pending_adds.clear ();
675 pending_removes.clear ();
676 pending_bounds.clear ();
677 pending_range_moves.clear ();
678 pending_contents_change = false;
679 pending_length = false;
682 /*************************************************************
684 *************************************************************/
687 Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
689 RegionLock rlock (this);
690 times = fabs (times);
692 int itimes = (int) floor (times);
694 framepos_t pos = position;
696 if (times == 1 && auto_partition){
697 partition(pos - 1, (pos + region->length()), true);
701 add_region_internal (region, pos);
702 pos += region->length();
707 /* note that itimes can be zero if we being asked to just
708 insert a single fraction of the region.
711 for (int i = 0; i < itimes; ++i) {
712 boost::shared_ptr<Region> copy = RegionFactory::create (region);
713 add_region_internal (copy, pos);
714 pos += region->length();
717 framecnt_t length = 0;
719 if (floor (times) != times) {
720 length = (framecnt_t) floor (region->length() * (times - floor (times)));
722 RegionFactory::region_name (name, region->name(), false);
727 plist.add (Properties::start, region->start());
728 plist.add (Properties::length, length);
729 plist.add (Properties::name, name);
730 plist.add (Properties::layer, region->layer());
732 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
733 add_region_internal (sub, pos);
737 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
741 Playlist::set_region_ownership ()
743 RegionLock rl (this);
744 RegionList::iterator i;
745 boost::weak_ptr<Playlist> pl (shared_from_this());
747 for (i = regions.begin(); i != regions.end(); ++i) {
748 (*i)->set_playlist (pl);
753 Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
755 if (region->data_type() != _type){
759 RegionSortByPosition cmp;
761 framecnt_t old_length = 0;
763 if (!holding_state()) {
764 old_length = _get_extent().second;
767 if (!first_set_state) {
768 boost::shared_ptr<Playlist> foo (shared_from_this());
769 region->set_playlist (boost::weak_ptr<Playlist>(foo));
772 region->set_position (position, this);
774 timestamp_layer_op (region);
776 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
777 all_regions.insert (region);
779 possibly_splice_unlocked (position, region->length(), region);
781 if (!holding_state ()) {
782 /* layers get assigned from XML state, and are not reset during undo/redo */
786 /* we need to notify the existence of new region before checking dependents. Ick. */
788 notify_region_added (region);
790 if (!holding_state ()) {
792 check_dependents (region, false);
794 if (old_length != _get_extent().second) {
795 notify_length_changed ();
799 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
805 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
807 RegionLock rlock (this);
809 bool old_sp = _splicing;
812 remove_region_internal (old);
813 add_region_internal (newr, pos);
817 possibly_splice_unlocked (pos, old->length() - newr->length());
821 Playlist::remove_region (boost::shared_ptr<Region> region)
823 RegionLock rlock (this);
824 remove_region_internal (region);
828 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
830 RegionList::iterator i;
831 framecnt_t old_length = 0;
834 if (!holding_state()) {
835 old_length = _get_extent().second;
840 region->set_playlist (boost::weak_ptr<Playlist>());
843 /* XXX should probably freeze here .... */
845 for (i = regions.begin(); i != regions.end(); ++i) {
848 framepos_t pos = (*i)->position();
849 framecnt_t distance = (*i)->length();
853 possibly_splice_unlocked (pos, -distance);
855 if (!holding_state ()) {
857 remove_dependents (region);
859 if (old_length != _get_extent().second) {
860 notify_length_changed ();
864 notify_region_removed (region);
874 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
876 if (Config->get_use_overlap_equivalency()) {
877 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
878 if ((*i)->overlap_equivalent (other)) {
879 results.push_back ((*i));
883 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
884 if ((*i)->equivalent (other)) {
885 results.push_back ((*i));
892 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
894 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
896 if ((*i) && (*i)->region_list_equivalent (other)) {
897 results.push_back (*i);
903 Playlist::partition (framepos_t start, framepos_t end, bool cut)
907 partition_internal (start, end, cut, thawlist);
909 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
910 (*i)->resume_property_changes ();
915 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
917 RegionList new_regions;
920 RegionLock rlock (this);
922 boost::shared_ptr<Region> region;
923 boost::shared_ptr<Region> current;
925 RegionList::iterator tmp;
927 framepos_t pos1, pos2, pos3, pos4;
931 /* need to work from a copy, because otherwise the regions we add during the process
932 get operated on as well.
935 RegionList copy = regions.rlist();
937 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
944 if (current->first_frame() >= start && current->last_frame() < end) {
947 remove_region_internal (current);
953 /* coverage will return OverlapStart if the start coincides
954 with the end point. we do not partition such a region,
955 so catch this special case.
958 if (current->first_frame() >= end) {
962 if ((overlap = current->coverage (start, end)) == OverlapNone) {
966 pos1 = current->position();
969 pos4 = current->last_frame();
971 if (overlap == OverlapInternal) {
972 /* split: we need 3 new regions, the front, middle and end.
973 cut: we need 2 regions, the front and end.
978 ---------------*************************------------
981 ---------------*****++++++++++++++++====------------
983 ---------------*****----------------====------------
988 /* "middle" ++++++ */
990 RegionFactory::region_name (new_name, current->name(), false);
994 plist.add (Properties::start, current->start() + (pos2 - pos1));
995 plist.add (Properties::length, pos3 - pos2);
996 plist.add (Properties::name, new_name);
997 plist.add (Properties::layer, regions.size());
998 plist.add (Properties::automatic, true);
999 plist.add (Properties::left_of_split, true);
1000 plist.add (Properties::right_of_split, true);
1002 region = RegionFactory::create (current, plist);
1003 add_region_internal (region, start);
1004 new_regions.push_back (region);
1009 RegionFactory::region_name (new_name, current->name(), false);
1013 plist.add (Properties::start, current->start() + (pos3 - pos1));
1014 plist.add (Properties::length, pos4 - pos3);
1015 plist.add (Properties::name, new_name);
1016 plist.add (Properties::layer, regions.size());
1017 plist.add (Properties::automatic, true);
1018 plist.add (Properties::right_of_split, true);
1020 region = RegionFactory::create (current, plist);
1022 add_region_internal (region, end);
1023 new_regions.push_back (region);
1027 current->suspend_property_changes ();
1028 thawlist.push_back (current);
1029 current->cut_end (pos2 - 1, this);
1031 } else if (overlap == OverlapEnd) {
1035 ---------------*************************------------
1038 ---------------**************+++++++++++------------
1040 ---------------**************-----------------------
1047 RegionFactory::region_name (new_name, current->name(), false);
1051 plist.add (Properties::start, current->start() + (pos2 - pos1));
1052 plist.add (Properties::length, pos4 - pos2);
1053 plist.add (Properties::name, new_name);
1054 plist.add (Properties::layer, regions.size());
1055 plist.add (Properties::automatic, true);
1056 plist.add (Properties::left_of_split, true);
1058 region = RegionFactory::create (current, plist);
1060 add_region_internal (region, start);
1061 new_regions.push_back (region);
1066 current->suspend_property_changes ();
1067 thawlist.push_back (current);
1068 current->cut_end (pos2 - 1, this);
1070 } else if (overlap == OverlapStart) {
1072 /* split: we need 2 regions: the front and the end.
1073 cut: just trim current to skip the cut area
1078 ---------------*************************------------
1082 ---------------****+++++++++++++++++++++------------
1084 -------------------*********************------------
1090 RegionFactory::region_name (new_name, current->name(), false);
1094 plist.add (Properties::start, current->start());
1095 plist.add (Properties::length, pos3 - pos1);
1096 plist.add (Properties::name, new_name);
1097 plist.add (Properties::layer, regions.size());
1098 plist.add (Properties::automatic, true);
1099 plist.add (Properties::right_of_split, true);
1101 region = RegionFactory::create (current, plist);
1103 add_region_internal (region, pos1);
1104 new_regions.push_back (region);
1109 current->suspend_property_changes ();
1110 thawlist.push_back (current);
1111 current->trim_front (pos3, this);
1112 } else if (overlap == OverlapExternal) {
1114 /* split: no split required.
1115 cut: remove the region.
1120 ---------------*************************------------
1124 ---------------*************************------------
1126 ----------------------------------------------------
1131 remove_region_internal (current);
1134 new_regions.push_back (current);
1138 in_partition = false;
1141 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1142 check_dependents (*i, false);
1146 boost::shared_ptr<Playlist>
1147 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1149 boost::shared_ptr<Playlist> ret;
1150 boost::shared_ptr<Playlist> pl;
1153 if (ranges.empty()) {
1154 return boost::shared_ptr<Playlist>();
1157 start = ranges.front().start;
1159 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1161 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1163 if (i == ranges.begin()) {
1167 /* paste the next section into the nascent playlist,
1168 offset to reflect the start of the first range we
1172 ret->paste (pl, (*i).start - start, 1.0f);
1179 boost::shared_ptr<Playlist>
1180 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1182 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1183 return cut_copy (pmf, ranges, result_is_hidden);
1186 boost::shared_ptr<Playlist>
1187 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1189 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1190 return cut_copy (pmf, ranges, result_is_hidden);
1193 boost::shared_ptr<Playlist>
1194 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1196 boost::shared_ptr<Playlist> the_copy;
1197 RegionList thawlist;
1200 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1201 string new_name = _name;
1205 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1206 return boost::shared_ptr<Playlist>();
1209 partition_internal (start, start+cnt-1, true, thawlist);
1211 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1212 (*i)->resume_property_changes();
1218 boost::shared_ptr<Playlist>
1219 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1223 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1224 string new_name = _name;
1228 cnt = min (_get_extent().second - start, cnt);
1229 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1233 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1235 times = fabs (times);
1238 RegionLock rl1 (this);
1239 RegionLock rl2 (other.get());
1241 framecnt_t const old_length = _get_extent().second;
1243 int itimes = (int) floor (times);
1244 framepos_t pos = position;
1245 framecnt_t const shift = other->_get_extent().second;
1246 layer_t top_layer = regions.size();
1249 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1250 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1252 /* put these new regions on top of all existing ones, but preserve
1253 the ordering they had in the original playlist.
1256 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1257 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1263 /* XXX shall we handle fractional cases at some point? */
1265 if (old_length != _get_extent().second) {
1266 notify_length_changed ();
1277 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1279 times = fabs (times);
1281 RegionLock rl (this);
1282 int itimes = (int) floor (times);
1283 framepos_t pos = position + 1;
1286 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1287 add_region_internal (copy, pos);
1288 pos += region->length();
1291 if (floor (times) != times) {
1292 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1294 RegionFactory::region_name (name, region->name(), false);
1299 plist.add (Properties::start, region->start());
1300 plist.add (Properties::length, length);
1301 plist.add (Properties::name, name);
1303 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1304 add_region_internal (sub, pos);
1310 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1312 RegionLock rlock (this);
1313 RegionList copy (regions.rlist());
1316 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1318 if ((*r)->last_frame() < at) {
1323 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1324 /* intersected region */
1325 if (!move_intersected) {
1330 /* do not move regions glued to music time - that
1331 has to be done separately.
1334 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1335 fixup.push_back (*r);
1339 (*r)->set_position ((*r)->position() + distance, this);
1342 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1343 (*r)->recompute_position_from_lock_style ();
1348 Playlist::split (framepos_t at)
1350 RegionLock rlock (this);
1351 RegionList copy (regions.rlist());
1353 /* use a copy since this operation can modify the region list
1356 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1357 _split_region (*r, at);
1362 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1364 RegionLock rl (this);
1365 _split_region (region, playlist_position);
1369 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1371 if (!region->covers (playlist_position)) {
1375 if (region->position() == playlist_position ||
1376 region->last_frame() == playlist_position) {
1380 boost::shared_ptr<Region> left;
1381 boost::shared_ptr<Region> right;
1382 frameoffset_t before;
1383 frameoffset_t after;
1387 /* split doesn't change anything about length, so don't try to splice */
1389 bool old_sp = _splicing;
1392 before = playlist_position - region->position();
1393 after = region->length() - before;
1395 RegionFactory::region_name (before_name, region->name(), false);
1400 plist.add (Properties::length, before);
1401 plist.add (Properties::name, before_name);
1402 plist.add (Properties::left_of_split, true);
1404 /* note: we must use the version of ::create with an offset here,
1405 since it supplies that offset to the Region constructor, which
1406 is necessary to get audio region gain envelopes right.
1408 left = RegionFactory::create (region, 0, plist);
1411 RegionFactory::region_name (after_name, region->name(), false);
1416 plist.add (Properties::length, after);
1417 plist.add (Properties::name, after_name);
1418 plist.add (Properties::right_of_split, true);
1420 /* same note as above */
1421 right = RegionFactory::create (region, before, plist);
1424 add_region_internal (left, region->position());
1425 add_region_internal (right, region->position() + before);
1427 uint64_t orig_layer_op = region->last_layer_op();
1428 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1429 if ((*i)->last_layer_op() > orig_layer_op) {
1430 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1434 left->set_last_layer_op ( orig_layer_op );
1435 right->set_last_layer_op ( orig_layer_op + 1);
1439 finalize_split_region (region, left, right);
1441 remove_region_internal (region);
1447 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1449 if (_splicing || in_set_state) {
1450 /* don't respond to splicing moves or state setting */
1454 if (_edit_mode == Splice) {
1455 splice_locked (at, distance, exclude);
1460 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1462 if (_splicing || in_set_state) {
1463 /* don't respond to splicing moves or state setting */
1467 if (_edit_mode == Splice) {
1468 splice_unlocked (at, distance, exclude);
1473 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1476 RegionLock rl (this);
1477 core_splice (at, distance, exclude);
1482 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1484 core_splice (at, distance, exclude);
1488 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1492 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1494 if (exclude && (*i) == exclude) {
1498 if ((*i)->position() >= at) {
1499 framepos_t new_pos = (*i)->position() + distance;
1502 } else if (new_pos >= max_framepos - (*i)->length()) {
1503 new_pos = max_framepos - (*i)->length();
1506 (*i)->set_position (new_pos, this);
1512 notify_length_changed ();
1516 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1518 if (in_set_state || _splicing || _nudging || _shuffling) {
1522 if (what_changed.contains (Properties::position)) {
1524 /* remove it from the list then add it back in
1525 the right place again.
1528 RegionSortByPosition cmp;
1530 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1532 if (i == regions.end()) {
1533 /* the region bounds are being modified but its not currently
1534 in the region list. we will use its bounds correctly when/if
1541 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1544 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1546 frameoffset_t delta = 0;
1548 if (what_changed.contains (Properties::position)) {
1549 delta = region->position() - region->last_position();
1552 if (what_changed.contains (Properties::length)) {
1553 delta += region->length() - region->last_length();
1557 possibly_splice (region->last_position() + region->last_length(), delta, region);
1560 if (holding_state ()) {
1561 pending_bounds.push_back (region);
1563 if (_session.config.get_layer_model() == MoveAddHigher) {
1564 /* it moved or changed length, so change the timestamp */
1565 timestamp_layer_op (region);
1568 notify_length_changed ();
1570 check_dependents (region, false);
1576 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1578 boost::shared_ptr<Region> region (weak_region.lock());
1584 /* this makes a virtual call to the right kind of playlist ... */
1586 region_changed (what_changed, region);
1590 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1592 PropertyChange our_interests;
1593 PropertyChange bounds;
1594 PropertyChange pos_and_length;
1597 if (in_set_state || in_flush) {
1601 our_interests.add (Properties::muted);
1602 our_interests.add (Properties::layer);
1603 our_interests.add (Properties::opaque);
1605 bounds.add (Properties::start);
1606 bounds.add (Properties::position);
1607 bounds.add (Properties::length);
1609 pos_and_length.add (Properties::position);
1610 pos_and_length.add (Properties::length);
1612 if (what_changed.contains (bounds)) {
1613 region_bounds_changed (what_changed, region);
1614 save = !(_splicing || _nudging);
1617 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1618 check_dependents (region, false);
1621 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1622 notify_region_moved (region);
1626 /* don't notify about layer changes, since we are the only object that can initiate
1627 them, and we notify in ::relayer()
1630 if (what_changed.contains (our_interests)) {
1638 Playlist::drop_regions ()
1640 RegionLock rl (this);
1642 all_regions.clear ();
1646 Playlist::clear (bool with_signals)
1649 RegionLock rl (this);
1651 region_state_changed_connections.drop_connections ();
1653 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1654 pending_removes.insert (*i);
1659 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1660 remove_dependents (*s);
1666 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1667 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1670 pending_removes.clear ();
1671 pending_length = false;
1673 pending_contents_change = false;
1679 /***********************************************************************
1681 **********************************************************************/
1683 Playlist::RegionList *
1684 Playlist::regions_at (framepos_t frame)
1687 RegionLock rlock (this);
1688 return find_regions_at (frame);
1692 Playlist::count_regions_at (framepos_t frame)
1694 RegionLock rlock (this);
1697 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1698 if ((*i)->covers (frame)) {
1706 boost::shared_ptr<Region>
1707 Playlist::top_region_at (framepos_t frame)
1710 RegionLock rlock (this);
1711 RegionList *rlist = find_regions_at (frame);
1712 boost::shared_ptr<Region> region;
1714 if (rlist->size()) {
1715 RegionSortByLayer cmp;
1717 region = rlist->back();
1724 boost::shared_ptr<Region>
1725 Playlist::top_unmuted_region_at (framepos_t frame)
1728 RegionLock rlock (this);
1729 RegionList *rlist = find_regions_at (frame);
1731 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1733 RegionList::iterator tmp = i;
1736 if ((*i)->muted()) {
1743 boost::shared_ptr<Region> region;
1745 if (rlist->size()) {
1746 RegionSortByLayer cmp;
1748 region = rlist->back();
1755 Playlist::RegionList*
1756 Playlist::regions_to_read (framepos_t start, framepos_t end)
1758 /* Caller must hold lock */
1760 RegionList covering;
1761 set<framepos_t> to_check;
1762 set<boost::shared_ptr<Region> > unique;
1764 to_check.insert (start);
1765 to_check.insert (end);
1767 DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1769 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1771 /* find all/any regions that span start+end */
1773 switch ((*i)->coverage (start, end)) {
1777 case OverlapInternal:
1778 covering.push_back (*i);
1779 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1783 to_check.insert ((*i)->position());
1784 if ((*i)->position() != 0) {
1785 to_check.insert ((*i)->position()-1);
1787 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1788 covering.push_back (*i);
1792 to_check.insert ((*i)->last_frame());
1793 to_check.insert ((*i)->last_frame()+1);
1794 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1795 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1796 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1797 covering.push_back (*i);
1800 case OverlapExternal:
1801 covering.push_back (*i);
1802 to_check.insert ((*i)->position());
1803 if ((*i)->position() != 0) {
1804 to_check.insert ((*i)->position()-1);
1806 to_check.insert ((*i)->last_frame());
1807 to_check.insert ((*i)->last_frame()+1);
1808 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1809 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1810 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1814 /* don't go too far */
1816 if ((*i)->position() > end) {
1821 RegionList* rlist = new RegionList;
1823 /* find all the regions that cover each position .... */
1825 if (covering.size() == 1) {
1827 rlist->push_back (covering.front());
1828 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1833 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1837 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1839 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1841 if ((*x)->covers (*t)) {
1842 here.push_back (*x);
1843 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1847 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1854 RegionSortByLayer cmp;
1857 /* ... and get the top/transparent regions at "here" */
1859 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1863 if ((*c)->opaque()) {
1865 /* the other regions at this position are hidden by this one */
1866 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1873 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1874 rlist->push_back (*s);
1877 if (rlist->size() > 1) {
1878 /* now sort by time order */
1880 RegionSortByPosition cmp;
1885 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1890 Playlist::RegionList *
1891 Playlist::find_regions_at (framepos_t frame)
1893 /* Caller must hold lock */
1895 RegionList *rlist = new RegionList;
1897 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1898 if ((*i)->covers (frame)) {
1899 rlist->push_back (*i);
1906 Playlist::RegionList *
1907 Playlist::regions_touched (framepos_t start, framepos_t end)
1909 RegionLock rlock (this);
1910 RegionList *rlist = new RegionList;
1912 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1913 if ((*i)->coverage (start, end) != OverlapNone) {
1914 rlist->push_back (*i);
1922 Playlist::find_next_transient (framepos_t from, int dir)
1924 RegionLock rlock (this);
1925 AnalysisFeatureList points;
1926 AnalysisFeatureList these_points;
1928 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1930 if ((*i)->last_frame() < from) {
1934 if ((*i)->first_frame() > from) {
1939 (*i)->get_transients (these_points);
1941 /* add first frame, just, err, because */
1943 these_points.push_back ((*i)->first_frame());
1945 points.insert (points.end(), these_points.begin(), these_points.end());
1946 these_points.clear ();
1949 if (points.empty()) {
1953 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1954 bool reached = false;
1957 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1962 if (reached && (*x) > from) {
1967 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1972 if (reached && (*x) < from) {
1981 boost::shared_ptr<Region>
1982 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1984 RegionLock rlock (this);
1985 boost::shared_ptr<Region> ret;
1986 framepos_t closest = max_framepos;
1988 bool end_iter = false;
1990 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1994 frameoffset_t distance;
1995 boost::shared_ptr<Region> r = (*i);
2000 pos = r->first_frame ();
2003 pos = r->last_frame ();
2006 pos = r->sync_position ();
2011 case 1: /* forwards */
2014 if ((distance = pos - frame) < closest) {
2023 default: /* backwards */
2026 if ((distance = frame - pos) < closest) {
2043 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2045 RegionLock rlock (this);
2047 framepos_t closest = max_framepos;
2048 framepos_t ret = -1;
2052 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2054 boost::shared_ptr<Region> r = (*i);
2055 frameoffset_t distance;
2057 if (r->first_frame() > frame) {
2059 distance = r->first_frame() - frame;
2061 if (distance < closest) {
2062 ret = r->first_frame();
2067 if (r->last_frame () > frame) {
2069 distance = r->last_frame () - frame;
2071 if (distance < closest) {
2072 ret = r->last_frame ();
2080 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2082 boost::shared_ptr<Region> r = (*i);
2083 frameoffset_t distance;
2085 if (r->last_frame() < frame) {
2087 distance = frame - r->last_frame();
2089 if (distance < closest) {
2090 ret = r->last_frame();
2095 if (r->first_frame() < frame) {
2097 distance = frame - r->first_frame();
2099 if (distance < closest) {
2100 ret = r->first_frame();
2111 /***********************************************************************/
2117 Playlist::mark_session_dirty ()
2119 if (!in_set_state && !holding_state ()) {
2120 _session.set_dirty();
2125 Playlist::rdiff (vector<Command*>& cmds) const
2127 RegionLock rlock (const_cast<Playlist *> (this));
2128 Stateful::rdiff (cmds);
2132 Playlist::clear_owned_changes ()
2134 RegionLock rlock (this);
2135 Stateful::clear_owned_changes ();
2139 Playlist::update (const RegionListProperty::ChangeRecord& change)
2141 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2142 name(), change.added.size(), change.removed.size()));
2145 /* add the added regions */
2146 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2147 add_region ((*i), (*i)->position());
2149 /* remove the removed regions */
2150 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2158 Playlist::set_state (const XMLNode& node, int version)
2162 XMLNodeConstIterator niter;
2163 XMLPropertyList plist;
2164 XMLPropertyConstIterator piter;
2166 boost::shared_ptr<Region> region;
2171 if (node.name() != "Playlist") {
2178 plist = node.properties();
2180 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2184 if (prop->name() == X_("name")) {
2185 _name = prop->value();
2187 } else if (prop->name() == X_("id")) {
2188 _id = prop->value();
2189 } else if (prop->name() == X_("orig_diskstream_id")) {
2190 _orig_diskstream_id = prop->value ();
2191 } else if (prop->name() == X_("frozen")) {
2192 _frozen = string_is_affirmative (prop->value());
2198 nlist = node.children();
2200 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2204 if (child->name() == "Region") {
2206 if ((prop = child->property ("id")) == 0) {
2207 error << _("region state node has no ID, ignored") << endmsg;
2211 ID id = prop->value ();
2213 if ((region = region_by_id (id))) {
2215 region->suspend_property_changes ();
2217 if (region->set_state (*child, version)) {
2218 region->resume_property_changes ();
2222 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2223 region->suspend_property_changes ();
2225 error << _("Playlist: cannot create region from XML") << endmsg;
2230 add_region (region, region->position(), 1.0);
2232 // So that layer_op ordering doesn't get screwed up
2233 region->set_last_layer_op( region->layer());
2234 region->resume_property_changes ();
2238 /* update dependents, which was not done during add_region_internal
2239 due to in_set_state being true
2242 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2243 check_dependents (*r, false);
2247 notify_contents_changed ();
2250 first_set_state = false;
2255 Playlist::get_state()
2257 return state (true);
2261 Playlist::get_template()
2263 return state (false);
2266 /** @param full_state true to include regions in the returned state, otherwise false.
2269 Playlist::state (bool full_state)
2271 XMLNode *node = new XMLNode (X_("Playlist"));
2274 node->add_property (X_("id"), id().to_s());
2275 node->add_property (X_("name"), _name);
2276 node->add_property (X_("type"), _type.to_string());
2278 _orig_diskstream_id.print (buf, sizeof (buf));
2279 node->add_property (X_("orig_diskstream_id"), buf);
2280 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2283 RegionLock rlock (this, false);
2285 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2286 node->add_child_nocopy ((*i)->get_state());
2291 node->add_child_copy (*_extra_xml);
2298 Playlist::empty() const
2300 RegionLock rlock (const_cast<Playlist *>(this), false);
2301 return regions.empty();
2305 Playlist::n_regions() const
2307 RegionLock rlock (const_cast<Playlist *>(this), false);
2308 return regions.size();
2311 pair<framecnt_t, framecnt_t>
2312 Playlist::get_extent () const
2314 RegionLock rlock (const_cast<Playlist *>(this), false);
2315 return _get_extent ();
2318 pair<framecnt_t, framecnt_t>
2319 Playlist::_get_extent () const
2321 pair<framecnt_t, framecnt_t> ext (max_framepos, 0);
2323 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2324 pair<framecnt_t, framecnt_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2325 if (e.first < ext.first) {
2326 ext.first = e.first;
2328 if (e.second > ext.second) {
2329 ext.second = e.second;
2337 Playlist::bump_name (string name, Session &session)
2339 string newname = name;
2342 newname = bump_name_once (newname, '.');
2343 } while (session.playlists->by_name (newname)!=NULL);
2350 Playlist::top_layer() const
2352 RegionLock rlock (const_cast<Playlist *> (this));
2355 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2356 top = max (top, (*i)->layer());
2362 Playlist::set_edit_mode (EditMode mode)
2367 /********************
2369 ********************/
2372 Playlist::relayer ()
2374 /* never compute layers when changing state for undo/redo or setting from XML */
2376 if (in_update || in_set_state) {
2380 bool changed = false;
2382 /* Build up a new list of regions on each layer, stored in a set of lists
2383 each of which represent some period of time on some layer. The idea
2384 is to avoid having to search the entire region list to establish whether
2385 each region overlaps another */
2387 /* how many pieces to divide this playlist's time up into */
2388 int const divisions = 512;
2390 /* find the start and end positions of the regions on this playlist */
2391 framepos_t start = INT64_MAX;
2393 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2394 start = min (start, (*i)->position());
2395 end = max (end, (*i)->position() + (*i)->length());
2398 /* hence the size of each time division */
2399 double const division_size = (end - start) / double (divisions);
2401 vector<vector<RegionList> > layers;
2402 layers.push_back (vector<RegionList> (divisions));
2404 /* we want to go through regions from desired lowest to desired highest layer,
2405 which depends on the layer model
2408 RegionList copy = regions.rlist();
2410 /* sort according to the model and the layering mode that we're in */
2412 if (_explicit_relayering) {
2414 copy.sort (RegionSortByLayerWithPending ());
2416 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2418 copy.sort (RegionSortByLastLayerOp ());
2423 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2425 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2426 (*i)->set_pending_explicit_relayer (false);
2428 /* find the time divisions that this region covers; if there are no regions on the list,
2429 division_size will equal 0 and in this case we'll just say that
2430 start_division = end_division = 0.
2432 int start_division = 0;
2433 int end_division = 0;
2435 if (division_size > 0) {
2436 start_division = floor ( ((*i)->position() - start) / division_size);
2437 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2438 if (end_division == divisions) {
2443 assert (divisions == 0 || end_division < divisions);
2445 /* find the lowest layer that this region can go on */
2446 size_t j = layers.size();
2448 /* try layer j - 1; it can go on if it overlaps no other region
2449 that is already on that layer
2452 bool overlap = false;
2453 for (int k = start_division; k <= end_division; ++k) {
2454 RegionList::iterator l = layers[j-1][k].begin ();
2455 while (l != layers[j-1][k].end()) {
2456 if ((*l)->overlap_equivalent (*i)) {
2469 /* overlap, so we must use layer j */
2476 if (j == layers.size()) {
2477 /* we need a new layer for this region */
2478 layers.push_back (vector<RegionList> (divisions));
2481 /* put a reference to this region in each of the divisions that it exists in */
2482 for (int k = start_division; k <= end_division; ++k) {
2483 layers[j][k].push_back (*i);
2486 if ((*i)->layer() != j) {
2490 (*i)->set_layer (j);
2494 notify_layering_changed ();
2498 /* XXX these layer functions are all deprecated */
2501 Playlist::raise_region (boost::shared_ptr<Region> region)
2503 uint32_t top = regions.size() - 1;
2504 layer_t target = region->layer() + 1U;
2506 if (target >= top) {
2507 /* its already at the effective top */
2511 move_region_to_layer (target, region, 1);
2515 Playlist::lower_region (boost::shared_ptr<Region> region)
2517 if (region->layer() == 0) {
2518 /* its already at the bottom */
2522 layer_t target = region->layer() - 1U;
2524 move_region_to_layer (target, region, -1);
2528 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2530 /* does nothing useful if layering mode is later=higher */
2531 switch (_session.config.get_layer_model()) {
2538 layer_t top = regions.size() - 1;
2540 if (region->layer() >= top) {
2541 /* already on the top */
2545 move_region_to_layer (top, region, 1);
2546 /* mark the region's last_layer_op as now, so that it remains on top when
2547 doing future relayers (until something else takes over)
2549 timestamp_layer_op (region);
2553 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2555 /* does nothing useful if layering mode is later=higher */
2556 switch (_session.config.get_layer_model()) {
2563 if (region->layer() == 0) {
2564 /* already on the bottom */
2568 move_region_to_layer (0, region, -1);
2569 /* force region's last layer op to zero so that it stays at the bottom
2570 when doing future relayers
2572 region->set_last_layer_op (0);
2576 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2578 RegionList::iterator i;
2579 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2580 list<LayerInfo> layerinfo;
2583 RegionLock rlock (const_cast<Playlist *> (this));
2585 for (i = regions.begin(); i != regions.end(); ++i) {
2595 /* region is moving up, move all regions on intermediate layers
2599 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2600 dest = (*i)->layer() - 1;
2607 /* region is moving down, move all regions on intermediate layers
2611 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2612 dest = (*i)->layer() + 1;
2622 newpair.second = dest;
2624 layerinfo.push_back (newpair);
2630 /* now reset the layers without holding the region lock */
2632 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2633 x->first->set_layer (x->second);
2636 region->set_layer (target_layer);
2638 /* now check all dependents, since we changed the layering */
2640 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2641 check_dependents (x->first, false);
2644 check_dependents (region, false);
2645 notify_layering_changed ();
2653 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2655 RegionList::iterator i;
2661 RegionLock rlock (const_cast<Playlist *> (this));
2663 for (i = regions.begin(); i != regions.end(); ++i) {
2665 if ((*i)->position() >= start) {
2671 if ((*i)->last_frame() > max_framepos - distance) {
2672 new_pos = max_framepos - (*i)->length();
2674 new_pos = (*i)->position() + distance;
2679 if ((*i)->position() > distance) {
2680 new_pos = (*i)->position() - distance;
2686 (*i)->set_position (new_pos, this);
2694 notify_length_changed ();
2699 boost::shared_ptr<Region>
2700 Playlist::find_region (const ID& id) const
2702 RegionLock rlock (const_cast<Playlist*> (this));
2704 /* searches all regions currently in use by the playlist */
2706 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2707 if ((*i)->id() == id) {
2712 return boost::shared_ptr<Region> ();
2716 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2718 RegionLock rlock (const_cast<Playlist*> (this));
2721 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2730 boost::shared_ptr<Region>
2731 Playlist::region_by_id (const ID& id) const
2733 /* searches all regions ever added to this playlist */
2735 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2736 if ((*i)->id() == id) {
2740 return boost::shared_ptr<Region> ();
2744 Playlist::dump () const
2746 boost::shared_ptr<Region> r;
2748 cerr << "Playlist \"" << _name << "\" " << endl
2749 << regions.size() << " regions "
2752 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2754 cerr << " " << r->name() << " ["
2755 << r->start() << "+" << r->length()
2765 Playlist::set_frozen (bool yn)
2771 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2773 region->set_last_layer_op (++layer_op_counter);
2778 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2782 if (region->locked()) {
2789 RegionLock rlock (const_cast<Playlist*> (this));
2794 RegionList::iterator next;
2796 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2797 if ((*i) == region) {
2801 if (next != regions.end()) {
2803 if ((*next)->locked()) {
2809 if ((*next)->position() != region->last_frame() + 1) {
2810 /* they didn't used to touch, so after shuffle,
2811 just have them swap positions.
2813 new_pos = (*next)->position();
2815 /* they used to touch, so after shuffle,
2816 make sure they still do. put the earlier
2817 region where the later one will end after
2820 new_pos = region->position() + (*next)->length();
2823 (*next)->set_position (region->position(), this);
2824 region->set_position (new_pos, this);
2826 /* avoid a full sort */
2828 regions.erase (i); // removes the region from the list */
2830 regions.insert (next, region); // adds it back after next
2839 RegionList::iterator prev = regions.end();
2841 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2842 if ((*i) == region) {
2844 if (prev != regions.end()) {
2846 if ((*prev)->locked()) {
2851 if (region->position() != (*prev)->last_frame() + 1) {
2852 /* they didn't used to touch, so after shuffle,
2853 just have them swap positions.
2855 new_pos = region->position();
2857 /* they used to touch, so after shuffle,
2858 make sure they still do. put the earlier
2859 one where the later one will end after
2861 new_pos = (*prev)->position() + region->length();
2864 region->set_position ((*prev)->position(), this);
2865 (*prev)->set_position (new_pos, this);
2867 /* avoid a full sort */
2869 regions.erase (i); // remove region
2870 regions.insert (prev, region); // insert region before prev
2886 check_dependents (region, false);
2888 notify_contents_changed();
2894 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2896 RegionLock rlock (const_cast<Playlist*> (this));
2898 if (regions.size() > 1) {
2906 Playlist::update_after_tempo_map_change ()
2908 RegionLock rlock (const_cast<Playlist*> (this));
2909 RegionList copy (regions.rlist());
2913 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2914 (*i)->update_position_after_tempo_map_change ();
2921 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2923 RegionLock rl (this, false);
2924 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2930 Playlist::set_explicit_relayering (bool e)
2932 if (e == false && _explicit_relayering == true) {
2934 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2935 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2936 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2937 at this point would keep regions on the same layers.
2939 From then on in, it's just you and your towel.
2942 RegionLock rl (this);
2943 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2944 (*i)->set_last_layer_op ((*i)->layer ());
2948 _explicit_relayering = e;
2953 Playlist::has_region_at (framepos_t const p) const
2955 RegionLock (const_cast<Playlist *> (this));
2957 RegionList::const_iterator i = regions.begin ();
2958 while (i != regions.end() && !(*i)->covers (p)) {
2962 return (i != regions.end());
2965 /** Remove any region that uses a given source */
2967 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
2969 RegionLock rl (this);
2971 RegionList::iterator i = regions.begin();
2972 while (i != regions.end()) {
2973 RegionList::iterator j = i;
2976 if ((*i)->uses_source (s)) {
2977 remove_region_internal (*i);