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/convert.h"
32 #include "pbd/failed_constructor.h"
33 #include "pbd/stateful_diff_command.h"
34 #include "pbd/xml++.h"
36 #include "ardour/debug.h"
37 #include "ardour/playlist.h"
38 #include "ardour/session.h"
39 #include "ardour/region.h"
40 #include "ardour/region_factory.h"
41 #include "ardour/playlist_factory.h"
42 #include "ardour/playlist_source.h"
43 #include "ardour/transient_detector.h"
44 #include "ardour/session_playlists.h"
45 #include "ardour/source_factory.h"
50 using namespace ARDOUR;
54 namespace Properties {
55 PBD::PropertyDescriptor<bool> regions;
59 struct ShowMeTheList {
60 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
62 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
64 boost::shared_ptr<Playlist> playlist;
68 struct RegionSortByLayer {
69 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
70 return a->layer() < b->layer();
74 struct RegionSortByLayerWithPending {
75 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
77 double p = a->layer ();
78 if (a->pending_explicit_relayer()) {
82 double q = b->layer ();
83 if (b->pending_explicit_relayer()) {
91 struct RegionSortByPosition {
92 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
93 return a->position() < b->position();
97 struct RegionSortByLastLayerOp {
98 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
99 return a->last_layer_op() < b->last_layer_op();
104 Playlist::make_property_quarks ()
106 Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
107 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n",
108 Properties::regions.property_id));
111 RegionListProperty::RegionListProperty (Playlist& pl)
112 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
118 RegionListProperty::RegionListProperty (RegionListProperty const & p)
119 : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
120 , _playlist (p._playlist)
126 RegionListProperty::clone () const
128 return new RegionListProperty (*this);
132 RegionListProperty::create () const
134 return new RegionListProperty (_playlist);
138 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
140 /* All regions (even those which are deleted) have their state saved by other
141 code, so we can just store ID here.
144 node.add_property ("id", region->id().to_s ());
147 boost::shared_ptr<Region>
148 RegionListProperty::get_content_from_xml (XMLNode const & node) const
150 XMLProperty const * prop = node.property ("id");
153 PBD::ID id (prop->value ());
155 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
158 ret = RegionFactory::region_by_id (id);
164 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
165 : SessionObject(sess, nom)
170 first_set_state = false;
175 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
176 : SessionObject(sess, "unnamed playlist")
181 const XMLProperty* prop = node.property("type");
182 assert(!prop || DataType(prop->value()) == _type);
186 _name = "unnamed"; /* reset by set_state */
189 /* set state called by derived class */
192 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
193 : SessionObject(other->_session, namestr)
195 , _type(other->_type)
196 , _orig_diskstream_id (other->_orig_diskstream_id)
201 other->copy_regions (tmp);
205 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
206 add_region_internal( (*x), (*x)->position());
211 _splicing = other->_splicing;
212 _nudging = other->_nudging;
213 _edit_mode = other->_edit_mode;
216 first_set_state = false;
218 in_partition = false;
220 _read_data_count = 0;
221 _frozen = other->_frozen;
223 layer_op_counter = other->layer_op_counter;
224 freeze_length = other->freeze_length;
227 Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
228 : SessionObject(other->_session, str)
230 , _type(other->_type)
231 , _orig_diskstream_id (other->_orig_diskstream_id)
233 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
235 framepos_t end = start + cnt - 1;
241 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
243 boost::shared_ptr<Region> region;
244 boost::shared_ptr<Region> new_region;
245 frameoffset_t offset = 0;
246 framepos_t position = 0;
253 overlap = region->coverage (start, end);
259 case OverlapInternal:
260 offset = start - region->position();
267 position = region->position() - start;
268 len = end - region->position();
272 offset = start - region->position();
274 len = region->length() - offset;
277 case OverlapExternal:
279 position = region->position() - start;
280 len = region->length();
284 RegionFactory::region_name (new_name, region->name(), false);
288 plist.add (Properties::start, region->start() + offset);
289 plist.add (Properties::length, len);
290 plist.add (Properties::name, new_name);
291 plist.add (Properties::layer, region->layer());
293 new_region = RegionFactory::RegionFactory::create (region, plist);
295 add_region_internal (new_region, position);
299 first_set_state = false;
301 /* this constructor does NOT notify others (session) */
308 InUse (true); /* EMIT SIGNAL */
319 InUse (false); /* EMIT SIGNAL */
324 Playlist::copy_regions (RegionList& newlist) const
326 RegionLock rlock (const_cast<Playlist *> (this));
328 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
329 newlist.push_back (RegionFactory::RegionFactory::create (*i, true));
334 Playlist::init (bool hide)
336 add_property (regions);
337 _xml_node_name = X_("Playlist");
339 g_atomic_int_set (&block_notifications, 0);
340 g_atomic_int_set (&ignore_state_changes, 0);
341 pending_contents_change = false;
342 pending_length = false;
343 pending_layering = false;
344 first_set_state = true;
352 _edit_mode = Config->get_edit_mode();
354 in_partition = false;
356 _read_data_count = 0;
358 layer_op_counter = 0;
360 _explicit_relayering = false;
363 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
364 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
366 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
369 Playlist::~Playlist ()
371 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
374 RegionLock rl (this);
376 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
377 (*i)->set_playlist (boost::shared_ptr<Playlist>());
381 /* GoingAway must be emitted by derived classes */
385 Playlist::_set_sort_id ()
388 Playlists are given names like <track name>.<id>
389 or <track name>.<edit group name>.<id> where id
390 is an integer. We extract the id and sort by that.
393 size_t dot_position = _name.val().find_last_of(".");
395 if (dot_position == string::npos) {
398 string t = _name.val().substr(dot_position + 1);
401 _sort_id = boost::lexical_cast<int>(t);
404 catch (boost::bad_lexical_cast e) {
411 Playlist::set_name (const string& str)
413 /* in a typical situation, a playlist is being used
414 by one diskstream and also is referenced by the
415 Session. if there are more references than that,
416 then don't change the name.
423 bool ret = SessionObject::set_name(str);
430 /***********************************************************************
431 CHANGE NOTIFICATION HANDLING
433 Notifications must be delayed till the region_lock is released. This
434 is necessary because handlers for the signals may need to acquire
435 the lock (e.g. to read from the playlist).
436 ***********************************************************************/
439 Playlist::begin_undo ()
446 Playlist::end_undo ()
455 delay_notifications ();
456 g_atomic_int_inc (&ignore_state_changes);
459 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
461 Playlist::thaw (bool from_undo)
463 g_atomic_int_dec_and_test (&ignore_state_changes);
464 release_notifications (from_undo);
469 Playlist::delay_notifications ()
471 g_atomic_int_inc (&block_notifications);
472 freeze_length = _get_extent().second;
475 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
477 Playlist::release_notifications (bool from_undo)
479 if (g_atomic_int_dec_and_test (&block_notifications)) {
480 flush_notifications (from_undo);
485 Playlist::notify_contents_changed ()
487 if (holding_state ()) {
488 pending_contents_change = true;
490 pending_contents_change = false;
491 ContentsChanged(); /* EMIT SIGNAL */
496 Playlist::notify_layering_changed ()
498 if (holding_state ()) {
499 pending_layering = true;
501 pending_layering = false;
502 LayeringChanged(); /* EMIT SIGNAL */
507 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
509 if (holding_state ()) {
510 pending_removes.insert (r);
511 pending_contents_change = true;
512 pending_length = true;
514 /* this might not be true, but we have to act
515 as though it could be.
517 pending_length = false;
518 LengthChanged (); /* EMIT SIGNAL */
519 pending_contents_change = false;
520 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
521 ContentsChanged (); /* EMIT SIGNAL */
526 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
528 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
530 if (holding_state ()) {
532 pending_range_moves.push_back (move);
536 list< Evoral::RangeMove<framepos_t> > m;
538 RangesMoved (m, false);
544 Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r)
546 if (r->position() >= r->last_position()) {
547 /* trimmed shorter */
551 Evoral::Range<framepos_t> const extra (r->position(), r->last_position());
553 if (holding_state ()) {
555 pending_region_extensions.push_back (extra);
559 list<Evoral::Range<framepos_t> > r;
567 Playlist::notify_region_end_trimmed (boost::shared_ptr<Region> r)
569 if (r->length() < r->last_length()) {
570 /* trimmed shorter */
573 Evoral::Range<framepos_t> const extra (r->position() + r->last_length(), r->position() + r->length());
575 if (holding_state ()) {
577 pending_region_extensions.push_back (extra);
581 list<Evoral::Range<framepos_t> > r;
589 Playlist::notify_region_added (boost::shared_ptr<Region> r)
591 /* the length change might not be true, but we have to act
592 as though it could be.
595 if (holding_state()) {
596 pending_adds.insert (r);
597 pending_contents_change = true;
598 pending_length = true;
601 pending_length = false;
602 LengthChanged (); /* EMIT SIGNAL */
603 pending_contents_change = false;
604 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
605 ContentsChanged (); /* EMIT SIGNAL */
610 Playlist::notify_length_changed ()
612 if (holding_state ()) {
613 pending_length = true;
615 pending_length = false;
616 LengthChanged(); /* EMIT SIGNAL */
617 pending_contents_change = false;
618 ContentsChanged (); /* EMIT SIGNAL */
622 /** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
624 Playlist::flush_notifications (bool from_undo)
626 set<boost::shared_ptr<Region> > dependent_checks_needed;
627 set<boost::shared_ptr<Region> >::iterator s;
628 uint32_t regions_changed = false;
629 bool check_length = false;
630 framecnt_t old_length = 0;
638 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
639 regions_changed = true;
640 if (!pending_length) {
641 old_length = _get_extent ().second;
646 /* we have no idea what order the regions ended up in pending
647 bounds (it could be based on selection order, for example).
648 so, to preserve layering in the "most recently moved is higher"
649 model, sort them by existing layer, then timestamp them.
652 // RegionSortByLayer cmp;
653 // pending_bounds.sort (cmp);
655 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
656 if (_session.config.get_layer_model() == MoveAddHigher) {
657 timestamp_layer_op (*r);
659 dependent_checks_needed.insert (*r);
662 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
663 remove_dependents (*s);
664 // cerr << _name << " sends RegionRemoved\n";
665 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
668 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
669 // cerr << _name << " sends RegionAdded\n";
670 /* don't emit RegionAdded signal until relayering is done,
671 so that the region is fully setup by the time
672 anyone hear's that its been added
674 dependent_checks_needed.insert (*s);
678 if (old_length != _get_extent().second) {
679 pending_length = true;
680 // cerr << _name << " length has changed\n";
684 if (pending_length || (freeze_length != _get_extent().second)) {
685 pending_length = false;
686 // cerr << _name << " sends LengthChanged\n";
687 LengthChanged(); /* EMIT SIGNAL */
690 if (regions_changed || pending_contents_change) {
694 pending_contents_change = false;
695 // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
696 ContentsChanged (); /* EMIT SIGNAL */
697 // cerr << _name << "done contents change @ " << get_microseconds() << endl;
700 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
701 (*s)->clear_changes ();
702 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
705 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
706 check_dependents (*s, false);
709 if (!pending_range_moves.empty ()) {
710 RangesMoved (pending_range_moves, from_undo);
713 if (!pending_region_extensions.empty ()) {
714 RegionsExtended (pending_region_extensions);
723 Playlist::clear_pending ()
725 pending_adds.clear ();
726 pending_removes.clear ();
727 pending_bounds.clear ();
728 pending_range_moves.clear ();
729 pending_region_extensions.clear ();
730 pending_contents_change = false;
731 pending_length = false;
734 /*************************************************************
736 *************************************************************/
739 Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
741 RegionLock rlock (this);
742 times = fabs (times);
744 int itimes = (int) floor (times);
746 framepos_t pos = position;
748 if (times == 1 && auto_partition){
749 partition(pos - 1, (pos + region->length()), true);
753 add_region_internal (region, pos);
754 pos += region->length();
759 /* note that itimes can be zero if we being asked to just
760 insert a single fraction of the region.
763 for (int i = 0; i < itimes; ++i) {
764 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
765 add_region_internal (copy, pos);
766 pos += region->length();
769 framecnt_t length = 0;
771 if (floor (times) != times) {
772 length = (framecnt_t) floor (region->length() * (times - floor (times)));
774 RegionFactory::region_name (name, region->name(), false);
779 plist.add (Properties::start, region->start());
780 plist.add (Properties::length, length);
781 plist.add (Properties::name, name);
782 plist.add (Properties::layer, region->layer());
784 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
785 add_region_internal (sub, pos);
789 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
793 Playlist::set_region_ownership ()
795 RegionLock rl (this);
796 RegionList::iterator i;
797 boost::weak_ptr<Playlist> pl (shared_from_this());
799 for (i = regions.begin(); i != regions.end(); ++i) {
800 (*i)->set_playlist (pl);
805 Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
807 if (region->data_type() != _type){
811 RegionSortByPosition cmp;
813 framecnt_t old_length = 0;
815 if (!holding_state()) {
816 old_length = _get_extent().second;
819 if (!first_set_state) {
820 boost::shared_ptr<Playlist> foo (shared_from_this());
821 region->set_playlist (boost::weak_ptr<Playlist>(foo));
824 region->set_position (position, this);
826 timestamp_layer_op (region);
828 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
829 all_regions.insert (region);
831 possibly_splice_unlocked (position, region->length(), region);
833 if (!holding_state ()) {
834 /* layers get assigned from XML state, and are not reset during undo/redo */
838 /* we need to notify the existence of new region before checking dependents. Ick. */
840 notify_region_added (region);
842 if (!holding_state ()) {
844 check_dependents (region, false);
846 if (old_length != _get_extent().second) {
847 notify_length_changed ();
851 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
857 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
859 RegionLock rlock (this);
861 bool old_sp = _splicing;
864 remove_region_internal (old);
865 add_region_internal (newr, pos);
869 possibly_splice_unlocked (pos, old->length() - newr->length());
873 Playlist::remove_region (boost::shared_ptr<Region> region)
875 RegionLock rlock (this);
876 remove_region_internal (region);
880 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
882 RegionList::iterator i;
883 framecnt_t old_length = 0;
886 if (!holding_state()) {
887 old_length = _get_extent().second;
892 region->set_playlist (boost::weak_ptr<Playlist>());
895 /* XXX should probably freeze here .... */
897 for (i = regions.begin(); i != regions.end(); ++i) {
900 framepos_t pos = (*i)->position();
901 framecnt_t distance = (*i)->length();
905 possibly_splice_unlocked (pos, -distance);
907 if (!holding_state ()) {
909 remove_dependents (region);
911 if (old_length != _get_extent().second) {
912 notify_length_changed ();
916 notify_region_removed (region);
926 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
928 if (Config->get_use_overlap_equivalency()) {
929 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
930 if ((*i)->overlap_equivalent (other)) {
931 results.push_back ((*i));
935 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
936 if ((*i)->equivalent (other)) {
937 results.push_back ((*i));
944 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
946 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
948 if ((*i) && (*i)->region_list_equivalent (other)) {
949 results.push_back (*i);
955 Playlist::partition (framepos_t start, framepos_t end, bool cut)
959 partition_internal (start, end, cut, thawlist);
961 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
962 (*i)->resume_property_changes ();
967 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
969 RegionList new_regions;
972 RegionLock rlock (this);
974 boost::shared_ptr<Region> region;
975 boost::shared_ptr<Region> current;
977 RegionList::iterator tmp;
979 framepos_t pos1, pos2, pos3, pos4;
983 /* need to work from a copy, because otherwise the regions we add during the process
984 get operated on as well.
987 RegionList copy = regions.rlist();
989 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
996 if (current->first_frame() >= start && current->last_frame() < end) {
999 remove_region_internal (current);
1005 /* coverage will return OverlapStart if the start coincides
1006 with the end point. we do not partition such a region,
1007 so catch this special case.
1010 if (current->first_frame() >= end) {
1014 if ((overlap = current->coverage (start, end)) == OverlapNone) {
1018 pos1 = current->position();
1021 pos4 = current->last_frame();
1023 if (overlap == OverlapInternal) {
1024 /* split: we need 3 new regions, the front, middle and end.
1025 cut: we need 2 regions, the front and end.
1030 ---------------*************************------------
1033 ---------------*****++++++++++++++++====------------
1035 ---------------*****----------------====------------
1040 /* "middle" ++++++ */
1042 RegionFactory::region_name (new_name, current->name(), false);
1046 plist.add (Properties::start, current->start() + (pos2 - pos1));
1047 plist.add (Properties::length, pos3 - pos2);
1048 plist.add (Properties::name, new_name);
1049 plist.add (Properties::layer, regions.size());
1050 plist.add (Properties::automatic, true);
1051 plist.add (Properties::left_of_split, true);
1052 plist.add (Properties::right_of_split, true);
1054 region = RegionFactory::create (current, plist);
1055 add_region_internal (region, start);
1056 new_regions.push_back (region);
1061 RegionFactory::region_name (new_name, current->name(), false);
1065 plist.add (Properties::start, current->start() + (pos3 - pos1));
1066 plist.add (Properties::length, pos4 - pos3);
1067 plist.add (Properties::name, new_name);
1068 plist.add (Properties::layer, regions.size());
1069 plist.add (Properties::automatic, true);
1070 plist.add (Properties::right_of_split, true);
1072 region = RegionFactory::create (current, plist);
1074 add_region_internal (region, end);
1075 new_regions.push_back (region);
1079 current->suspend_property_changes ();
1080 thawlist.push_back (current);
1081 current->cut_end (pos2 - 1, this);
1083 } else if (overlap == OverlapEnd) {
1087 ---------------*************************------------
1090 ---------------**************+++++++++++------------
1092 ---------------**************-----------------------
1099 RegionFactory::region_name (new_name, current->name(), false);
1103 plist.add (Properties::start, current->start() + (pos2 - pos1));
1104 plist.add (Properties::length, pos4 - pos2);
1105 plist.add (Properties::name, new_name);
1106 plist.add (Properties::layer, regions.size());
1107 plist.add (Properties::automatic, true);
1108 plist.add (Properties::left_of_split, true);
1110 region = RegionFactory::create (current, plist);
1112 add_region_internal (region, start);
1113 new_regions.push_back (region);
1118 current->suspend_property_changes ();
1119 thawlist.push_back (current);
1120 current->cut_end (pos2 - 1, this);
1122 } else if (overlap == OverlapStart) {
1124 /* split: we need 2 regions: the front and the end.
1125 cut: just trim current to skip the cut area
1130 ---------------*************************------------
1134 ---------------****+++++++++++++++++++++------------
1136 -------------------*********************------------
1142 RegionFactory::region_name (new_name, current->name(), false);
1146 plist.add (Properties::start, current->start());
1147 plist.add (Properties::length, pos3 - pos1);
1148 plist.add (Properties::name, new_name);
1149 plist.add (Properties::layer, regions.size());
1150 plist.add (Properties::automatic, true);
1151 plist.add (Properties::right_of_split, true);
1153 region = RegionFactory::create (current, plist);
1155 add_region_internal (region, pos1);
1156 new_regions.push_back (region);
1161 current->suspend_property_changes ();
1162 thawlist.push_back (current);
1163 current->trim_front (pos3, this);
1164 } else if (overlap == OverlapExternal) {
1166 /* split: no split required.
1167 cut: remove the region.
1172 ---------------*************************------------
1176 ---------------*************************------------
1178 ----------------------------------------------------
1183 remove_region_internal (current);
1186 new_regions.push_back (current);
1190 in_partition = false;
1193 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1194 check_dependents (*i, false);
1198 boost::shared_ptr<Playlist>
1199 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1201 boost::shared_ptr<Playlist> ret;
1202 boost::shared_ptr<Playlist> pl;
1205 if (ranges.empty()) {
1206 return boost::shared_ptr<Playlist>();
1209 start = ranges.front().start;
1211 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1213 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1215 if (i == ranges.begin()) {
1219 /* paste the next section into the nascent playlist,
1220 offset to reflect the start of the first range we
1224 ret->paste (pl, (*i).start - start, 1.0f);
1231 boost::shared_ptr<Playlist>
1232 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1234 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1235 return cut_copy (pmf, ranges, result_is_hidden);
1238 boost::shared_ptr<Playlist>
1239 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1241 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1242 return cut_copy (pmf, ranges, result_is_hidden);
1245 boost::shared_ptr<Playlist>
1246 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1248 boost::shared_ptr<Playlist> the_copy;
1249 RegionList thawlist;
1252 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1253 string new_name = _name;
1257 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1258 return boost::shared_ptr<Playlist>();
1261 partition_internal (start, start+cnt-1, true, thawlist);
1263 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1264 (*i)->resume_property_changes();
1270 boost::shared_ptr<Playlist>
1271 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1275 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1276 string new_name = _name;
1280 cnt = min (_get_extent().second - start, cnt);
1281 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1285 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1287 times = fabs (times);
1290 RegionLock rl1 (this);
1291 RegionLock rl2 (other.get());
1293 framecnt_t const old_length = _get_extent().second;
1295 int itimes = (int) floor (times);
1296 framepos_t pos = position;
1297 framecnt_t const shift = other->_get_extent().second;
1298 layer_t top_layer = regions.size();
1301 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1302 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1304 /* put these new regions on top of all existing ones, but preserve
1305 the ordering they had in the original playlist.
1308 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1309 add_region_internal (copy_of_region, (*i)->position() + pos);
1315 /* XXX shall we handle fractional cases at some point? */
1317 if (old_length != _get_extent().second) {
1318 notify_length_changed ();
1329 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1331 times = fabs (times);
1333 RegionLock rl (this);
1334 int itimes = (int) floor (times);
1335 framepos_t pos = position + 1;
1338 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1339 add_region_internal (copy, pos);
1340 pos += region->length();
1343 if (floor (times) != times) {
1344 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1346 RegionFactory::region_name (name, region->name(), false);
1351 plist.add (Properties::start, region->start());
1352 plist.add (Properties::length, length);
1353 plist.add (Properties::name, name);
1355 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1356 add_region_internal (sub, pos);
1362 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1364 RegionLock rlock (this);
1365 RegionList copy (regions.rlist());
1368 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1370 if ((*r)->last_frame() < at) {
1375 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1376 /* intersected region */
1377 if (!move_intersected) {
1382 /* do not move regions glued to music time - that
1383 has to be done separately.
1386 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1387 fixup.push_back (*r);
1391 (*r)->set_position ((*r)->position() + distance, this);
1394 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1395 (*r)->recompute_position_from_lock_style ();
1400 Playlist::split (framepos_t at)
1402 RegionLock rlock (this);
1403 RegionList copy (regions.rlist());
1405 /* use a copy since this operation can modify the region list
1408 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1409 _split_region (*r, at);
1414 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1416 RegionLock rl (this);
1417 _split_region (region, playlist_position);
1421 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1423 if (!region->covers (playlist_position)) {
1427 if (region->position() == playlist_position ||
1428 region->last_frame() == playlist_position) {
1432 boost::shared_ptr<Region> left;
1433 boost::shared_ptr<Region> right;
1434 frameoffset_t before;
1435 frameoffset_t after;
1439 /* split doesn't change anything about length, so don't try to splice */
1441 bool old_sp = _splicing;
1444 before = playlist_position - region->position();
1445 after = region->length() - before;
1447 RegionFactory::region_name (before_name, region->name(), false);
1452 plist.add (Properties::position, region->position ());
1453 plist.add (Properties::length, before);
1454 plist.add (Properties::name, before_name);
1455 plist.add (Properties::left_of_split, true);
1457 /* note: we must use the version of ::create with an offset here,
1458 since it supplies that offset to the Region constructor, which
1459 is necessary to get audio region gain envelopes right.
1461 left = RegionFactory::create (region, 0, plist);
1464 RegionFactory::region_name (after_name, region->name(), false);
1469 plist.add (Properties::position, region->position() + before);
1470 plist.add (Properties::length, after);
1471 plist.add (Properties::name, after_name);
1472 plist.add (Properties::right_of_split, true);
1474 /* same note as above */
1475 right = RegionFactory::create (region, before, plist);
1478 add_region_internal (left, region->position());
1479 add_region_internal (right, region->position() + before);
1481 uint64_t orig_layer_op = region->last_layer_op();
1482 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1483 if ((*i)->last_layer_op() > orig_layer_op) {
1484 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1488 left->set_last_layer_op ( orig_layer_op );
1489 right->set_last_layer_op ( orig_layer_op + 1);
1493 finalize_split_region (region, left, right);
1495 remove_region_internal (region);
1501 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1503 if (_splicing || in_set_state) {
1504 /* don't respond to splicing moves or state setting */
1508 if (_edit_mode == Splice) {
1509 splice_locked (at, distance, exclude);
1514 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1516 if (_splicing || in_set_state) {
1517 /* don't respond to splicing moves or state setting */
1521 if (_edit_mode == Splice) {
1522 splice_unlocked (at, distance, exclude);
1527 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1530 RegionLock rl (this);
1531 core_splice (at, distance, exclude);
1536 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1538 core_splice (at, distance, exclude);
1542 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1546 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1548 if (exclude && (*i) == exclude) {
1552 if ((*i)->position() >= at) {
1553 framepos_t new_pos = (*i)->position() + distance;
1556 } else if (new_pos >= max_framepos - (*i)->length()) {
1557 new_pos = max_framepos - (*i)->length();
1560 (*i)->set_position (new_pos, this);
1566 notify_length_changed ();
1570 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1572 if (in_set_state || _splicing || _nudging || _shuffling) {
1576 if (what_changed.contains (Properties::position)) {
1578 /* remove it from the list then add it back in
1579 the right place again.
1582 RegionSortByPosition cmp;
1584 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1586 if (i == regions.end()) {
1587 /* the region bounds are being modified but its not currently
1588 in the region list. we will use its bounds correctly when/if
1595 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1598 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1600 frameoffset_t delta = 0;
1602 if (what_changed.contains (Properties::position)) {
1603 delta = region->position() - region->last_position();
1606 if (what_changed.contains (Properties::length)) {
1607 delta += region->length() - region->last_length();
1611 possibly_splice (region->last_position() + region->last_length(), delta, region);
1614 if (holding_state ()) {
1615 pending_bounds.push_back (region);
1617 if (_session.config.get_layer_model() == MoveAddHigher) {
1618 /* it moved or changed length, so change the timestamp */
1619 timestamp_layer_op (region);
1622 notify_length_changed ();
1624 check_dependents (region, false);
1630 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1632 boost::shared_ptr<Region> region (weak_region.lock());
1638 /* this makes a virtual call to the right kind of playlist ... */
1640 region_changed (what_changed, region);
1644 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1646 PropertyChange our_interests;
1647 PropertyChange bounds;
1648 PropertyChange pos_and_length;
1651 if (in_set_state || in_flush) {
1655 our_interests.add (Properties::muted);
1656 our_interests.add (Properties::layer);
1657 our_interests.add (Properties::opaque);
1659 bounds.add (Properties::start);
1660 bounds.add (Properties::position);
1661 bounds.add (Properties::length);
1663 pos_and_length.add (Properties::position);
1664 pos_and_length.add (Properties::length);
1666 if (what_changed.contains (bounds)) {
1667 region_bounds_changed (what_changed, region);
1668 save = !(_splicing || _nudging);
1671 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1672 check_dependents (region, false);
1675 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1676 notify_region_moved (region);
1677 } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1678 notify_region_end_trimmed (region);
1679 } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1680 notify_region_start_trimmed (region);
1683 /* don't notify about layer changes, since we are the only object that can initiate
1684 them, and we notify in ::relayer()
1687 if (what_changed.contains (our_interests)) {
1695 Playlist::drop_regions ()
1697 RegionLock rl (this);
1699 all_regions.clear ();
1703 Playlist::sync_all_regions_with_regions ()
1705 RegionLock rl (this);
1707 all_regions.clear ();
1709 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1710 all_regions.insert (*i);
1715 Playlist::clear (bool with_signals)
1718 RegionLock rl (this);
1720 region_state_changed_connections.drop_connections ();
1722 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1723 pending_removes.insert (*i);
1728 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1729 remove_dependents (*s);
1735 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1736 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1739 pending_removes.clear ();
1740 pending_length = false;
1742 pending_contents_change = false;
1748 /***********************************************************************
1750 **********************************************************************/
1752 Playlist::RegionList *
1753 Playlist::regions_at (framepos_t frame)
1756 RegionLock rlock (this);
1757 return find_regions_at (frame);
1761 Playlist::count_regions_at (framepos_t frame) const
1763 RegionLock rlock (const_cast<Playlist*>(this));
1766 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1767 if ((*i)->covers (frame)) {
1775 boost::shared_ptr<Region>
1776 Playlist::top_region_at (framepos_t frame)
1779 RegionLock rlock (this);
1780 RegionList *rlist = find_regions_at (frame);
1781 boost::shared_ptr<Region> region;
1783 if (rlist->size()) {
1784 RegionSortByLayer cmp;
1786 region = rlist->back();
1793 boost::shared_ptr<Region>
1794 Playlist::top_unmuted_region_at (framepos_t frame)
1797 RegionLock rlock (this);
1798 RegionList *rlist = find_regions_at (frame);
1800 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1802 RegionList::iterator tmp = i;
1805 if ((*i)->muted()) {
1812 boost::shared_ptr<Region> region;
1814 if (rlist->size()) {
1815 RegionSortByLayer cmp;
1817 region = rlist->back();
1824 Playlist::RegionList*
1825 Playlist::regions_to_read (framepos_t start, framepos_t end)
1827 /* Caller must hold lock */
1829 RegionList covering;
1830 set<framepos_t> to_check;
1831 set<boost::shared_ptr<Region> > unique;
1833 to_check.insert (start);
1834 to_check.insert (end);
1836 DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1838 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1840 /* find all/any regions that span start+end */
1842 switch ((*i)->coverage (start, end)) {
1846 case OverlapInternal:
1847 covering.push_back (*i);
1848 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1852 to_check.insert ((*i)->position());
1853 if ((*i)->position() != 0) {
1854 to_check.insert ((*i)->position()-1);
1856 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1857 covering.push_back (*i);
1861 to_check.insert ((*i)->last_frame());
1862 to_check.insert ((*i)->last_frame()+1);
1863 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1864 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1865 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1866 covering.push_back (*i);
1869 case OverlapExternal:
1870 covering.push_back (*i);
1871 to_check.insert ((*i)->position());
1872 if ((*i)->position() != 0) {
1873 to_check.insert ((*i)->position()-1);
1875 to_check.insert ((*i)->last_frame());
1876 to_check.insert ((*i)->last_frame()+1);
1877 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1878 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1879 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1883 /* don't go too far */
1885 if ((*i)->position() > end) {
1890 RegionList* rlist = new RegionList;
1892 /* find all the regions that cover each position .... */
1894 if (covering.size() == 1) {
1896 rlist->push_back (covering.front());
1897 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1902 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1906 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1908 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1910 if ((*x)->covers (*t)) {
1911 here.push_back (*x);
1912 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1916 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1923 RegionSortByLayer cmp;
1926 /* ... and get the top/transparent regions at "here" */
1928 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1932 if ((*c)->opaque()) {
1934 /* the other regions at this position are hidden by this one */
1935 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1942 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1943 rlist->push_back (*s);
1946 if (rlist->size() > 1) {
1947 /* now sort by time order */
1949 RegionSortByPosition cmp;
1954 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1959 Playlist::RegionList *
1960 Playlist::find_regions_at (framepos_t frame)
1962 /* Caller must hold lock */
1964 RegionList *rlist = new RegionList;
1966 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1967 if ((*i)->covers (frame)) {
1968 rlist->push_back (*i);
1975 Playlist::RegionList *
1976 Playlist::regions_touched (framepos_t start, framepos_t end)
1978 RegionLock rlock (this);
1979 RegionList *rlist = new RegionList;
1981 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1982 if ((*i)->coverage (start, end) != OverlapNone) {
1983 rlist->push_back (*i);
1991 Playlist::find_next_transient (framepos_t from, int dir)
1993 RegionLock rlock (this);
1994 AnalysisFeatureList points;
1995 AnalysisFeatureList these_points;
1997 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1999 if ((*i)->last_frame() < from) {
2003 if ((*i)->first_frame() > from) {
2008 (*i)->get_transients (these_points);
2010 /* add first frame, just, err, because */
2012 these_points.push_back ((*i)->first_frame());
2014 points.insert (points.end(), these_points.begin(), these_points.end());
2015 these_points.clear ();
2018 if (points.empty()) {
2022 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
2023 bool reached = false;
2026 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
2031 if (reached && (*x) > from) {
2036 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2041 if (reached && (*x) < from) {
2050 boost::shared_ptr<Region>
2051 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
2053 RegionLock rlock (this);
2054 boost::shared_ptr<Region> ret;
2055 framepos_t closest = max_framepos;
2057 bool end_iter = false;
2059 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2063 frameoffset_t distance;
2064 boost::shared_ptr<Region> r = (*i);
2069 pos = r->first_frame ();
2072 pos = r->last_frame ();
2075 pos = r->sync_position ();
2080 case 1: /* forwards */
2083 if ((distance = pos - frame) < closest) {
2092 default: /* backwards */
2095 if ((distance = frame - pos) < closest) {
2112 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2114 RegionLock rlock (this);
2116 framepos_t closest = max_framepos;
2117 framepos_t ret = -1;
2121 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2123 boost::shared_ptr<Region> r = (*i);
2124 frameoffset_t distance;
2126 if (r->first_frame() > frame) {
2128 distance = r->first_frame() - frame;
2130 if (distance < closest) {
2131 ret = r->first_frame();
2136 if (r->last_frame () > frame) {
2138 distance = r->last_frame () - frame;
2140 if (distance < closest) {
2141 ret = r->last_frame ();
2149 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2151 boost::shared_ptr<Region> r = (*i);
2152 frameoffset_t distance;
2154 if (r->last_frame() < frame) {
2156 distance = frame - r->last_frame();
2158 if (distance < closest) {
2159 ret = r->last_frame();
2164 if (r->first_frame() < frame) {
2166 distance = frame - r->first_frame();
2168 if (distance < closest) {
2169 ret = r->first_frame();
2180 /***********************************************************************/
2186 Playlist::mark_session_dirty ()
2188 if (!in_set_state && !holding_state ()) {
2189 _session.set_dirty();
2194 Playlist::rdiff (vector<Command*>& cmds) const
2196 RegionLock rlock (const_cast<Playlist *> (this));
2197 Stateful::rdiff (cmds);
2201 Playlist::clear_owned_changes ()
2203 RegionLock rlock (this);
2204 Stateful::clear_owned_changes ();
2208 Playlist::update (const RegionListProperty::ChangeRecord& change)
2210 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2211 name(), change.added.size(), change.removed.size()));
2214 /* add the added regions */
2215 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2216 add_region ((*i), (*i)->position());
2218 /* remove the removed regions */
2219 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2227 Playlist::load_nested_sources (const XMLNode& node)
2230 XMLNodeConstIterator niter;
2232 nlist = node.children();
2234 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2235 if ((*niter)->name() == "Source") {
2237 SourceFactory::create (_session, **niter, true);
2239 catch (failed_constructor& err) {
2240 error << string_compose (_("Cannot reconstruct nested source for playlist %1"), name()) << endmsg;
2247 Playlist::set_state (const XMLNode& node, int version)
2251 XMLNodeConstIterator niter;
2252 XMLPropertyList plist;
2253 XMLPropertyConstIterator piter;
2255 boost::shared_ptr<Region> region;
2260 if (node.name() != "Playlist") {
2267 plist = node.properties();
2269 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2273 if (prop->name() == X_("name")) {
2274 _name = prop->value();
2276 } else if (prop->name() == X_("id")) {
2277 _id = prop->value();
2278 } else if (prop->name() == X_("orig-diskstream-id")) {
2279 _orig_diskstream_id = prop->value ();
2280 } else if (prop->name() == X_("frozen")) {
2281 _frozen = string_is_affirmative (prop->value());
2282 } else if (prop->name() == X_("combine-ops")) {
2283 _combine_ops = atoi (prop->value());
2289 nlist = node.children();
2291 /* find the "Nested" node, if any, and recreate the PlaylistSources
2295 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2298 if (child->name() == "Nested") {
2299 load_nested_sources (*child);
2304 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2308 if (child->name() == "Region") {
2310 if ((prop = child->property ("id")) == 0) {
2311 error << _("region state node has no ID, ignored") << endmsg;
2315 ID id = prop->value ();
2317 if ((region = region_by_id (id))) {
2319 region->suspend_property_changes ();
2321 if (region->set_state (*child, version)) {
2322 region->resume_property_changes ();
2326 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2327 region->suspend_property_changes ();
2329 error << _("Playlist: cannot create region from XML") << endmsg;
2334 add_region (region, region->position(), 1.0);
2336 // So that layer_op ordering doesn't get screwed up
2337 region->set_last_layer_op( region->layer());
2338 region->resume_property_changes ();
2343 /* update dependents, which was not done during add_region_internal
2344 due to in_set_state being true
2347 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2348 check_dependents (*r, false);
2352 notify_contents_changed ();
2355 first_set_state = false;
2360 Playlist::get_state()
2362 return state (true);
2366 Playlist::get_template()
2368 return state (false);
2371 /** @param full_state true to include regions in the returned state, otherwise false.
2374 Playlist::state (bool full_state)
2376 XMLNode *node = new XMLNode (X_("Playlist"));
2379 node->add_property (X_("id"), id().to_s());
2380 node->add_property (X_("name"), _name);
2381 node->add_property (X_("type"), _type.to_string());
2383 _orig_diskstream_id.print (buf, sizeof (buf));
2384 node->add_property (X_("orig-diskstream-id"), buf);
2385 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2388 RegionLock rlock (this, false);
2389 XMLNode* nested_node = 0;
2391 snprintf (buf, sizeof (buf), "%u", _combine_ops);
2392 node->add_property ("combine-ops", buf);
2394 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2395 if ((*i)->max_source_level() > 0) {
2398 nested_node = new XMLNode (X_("Nested"));
2401 /* region is compound - get its playlist and
2402 store that before we list the region that
2406 const SourceList& sl ((*i)->sources());
2408 for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
2409 nested_node->add_child_nocopy ((*s)->get_state ());
2415 node->add_child_nocopy (*nested_node);
2418 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2419 node->add_child_nocopy ((*i)->get_state());
2424 node->add_child_copy (*_extra_xml);
2431 Playlist::empty() const
2433 RegionLock rlock (const_cast<Playlist *>(this), false);
2434 return regions.empty();
2438 Playlist::n_regions() const
2440 RegionLock rlock (const_cast<Playlist *>(this), false);
2441 return regions.size();
2444 pair<framepos_t, framepos_t>
2445 Playlist::get_extent () const
2447 RegionLock rlock (const_cast<Playlist *>(this), false);
2448 return _get_extent ();
2451 pair<framepos_t, framepos_t>
2452 Playlist::_get_extent () const
2454 pair<framepos_t, framepos_t> ext (max_framepos, 0);
2456 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2457 pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2458 if (e.first < ext.first) {
2459 ext.first = e.first;
2461 if (e.second > ext.second) {
2462 ext.second = e.second;
2470 Playlist::bump_name (string name, Session &session)
2472 string newname = name;
2475 newname = bump_name_once (newname, '.');
2476 } while (session.playlists->by_name (newname)!=NULL);
2483 Playlist::top_layer() const
2485 RegionLock rlock (const_cast<Playlist *> (this));
2488 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2489 top = max (top, (*i)->layer());
2495 Playlist::set_edit_mode (EditMode mode)
2500 /********************
2502 ********************/
2505 Playlist::relayer ()
2507 /* never compute layers when changing state for undo/redo or setting from XML */
2509 if (in_update || in_set_state) {
2513 bool changed = false;
2515 /* Build up a new list of regions on each layer, stored in a set of lists
2516 each of which represent some period of time on some layer. The idea
2517 is to avoid having to search the entire region list to establish whether
2518 each region overlaps another */
2520 /* how many pieces to divide this playlist's time up into */
2521 int const divisions = 512;
2523 /* find the start and end positions of the regions on this playlist */
2524 framepos_t start = INT64_MAX;
2526 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2527 start = min (start, (*i)->position());
2528 end = max (end, (*i)->position() + (*i)->length());
2531 /* hence the size of each time division */
2532 double const division_size = (end - start) / double (divisions);
2534 vector<vector<RegionList> > layers;
2535 layers.push_back (vector<RegionList> (divisions));
2537 /* we want to go through regions from desired lowest to desired highest layer,
2538 which depends on the layer model
2541 RegionList copy = regions.rlist();
2543 /* sort according to the model and the layering mode that we're in */
2545 if (_explicit_relayering) {
2547 copy.sort (RegionSortByLayerWithPending ());
2549 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2551 copy.sort (RegionSortByLastLayerOp ());
2556 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2558 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2559 (*i)->set_pending_explicit_relayer (false);
2561 /* find the time divisions that this region covers; if there are no regions on the list,
2562 division_size will equal 0 and in this case we'll just say that
2563 start_division = end_division = 0.
2565 int start_division = 0;
2566 int end_division = 0;
2568 if (division_size > 0) {
2569 start_division = floor ( ((*i)->position() - start) / division_size);
2570 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2571 if (end_division == divisions) {
2576 assert (divisions == 0 || end_division < divisions);
2578 /* find the lowest layer that this region can go on */
2579 size_t j = layers.size();
2581 /* try layer j - 1; it can go on if it overlaps no other region
2582 that is already on that layer
2585 bool overlap = false;
2586 for (int k = start_division; k <= end_division; ++k) {
2587 RegionList::iterator l = layers[j-1][k].begin ();
2588 while (l != layers[j-1][k].end()) {
2589 if ((*l)->overlap_equivalent (*i)) {
2602 /* overlap, so we must use layer j */
2609 if (j == layers.size()) {
2610 /* we need a new layer for this region */
2611 layers.push_back (vector<RegionList> (divisions));
2614 /* put a reference to this region in each of the divisions that it exists in */
2615 for (int k = start_division; k <= end_division; ++k) {
2616 layers[j][k].push_back (*i);
2619 if ((*i)->layer() != j) {
2623 (*i)->set_layer (j);
2627 notify_layering_changed ();
2631 /* XXX these layer functions are all deprecated */
2634 Playlist::raise_region (boost::shared_ptr<Region> region)
2636 uint32_t top = regions.size() - 1;
2637 layer_t target = region->layer() + 1U;
2639 if (target >= top) {
2640 /* its already at the effective top */
2644 move_region_to_layer (target, region, 1);
2648 Playlist::lower_region (boost::shared_ptr<Region> region)
2650 if (region->layer() == 0) {
2651 /* its already at the bottom */
2655 layer_t target = region->layer() - 1U;
2657 move_region_to_layer (target, region, -1);
2661 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2663 /* does nothing useful if layering mode is later=higher */
2664 switch (_session.config.get_layer_model()) {
2671 layer_t top = regions.size() - 1;
2673 if (region->layer() >= top) {
2674 /* already on the top */
2678 move_region_to_layer (top, region, 1);
2679 /* mark the region's last_layer_op as now, so that it remains on top when
2680 doing future relayers (until something else takes over)
2682 timestamp_layer_op (region);
2686 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2688 /* does nothing useful if layering mode is later=higher */
2689 switch (_session.config.get_layer_model()) {
2696 if (region->layer() == 0) {
2697 /* already on the bottom */
2701 move_region_to_layer (0, region, -1);
2702 /* force region's last layer op to zero so that it stays at the bottom
2703 when doing future relayers
2705 region->set_last_layer_op (0);
2709 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2711 RegionList::iterator i;
2712 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2713 list<LayerInfo> layerinfo;
2716 RegionLock rlock (const_cast<Playlist *> (this));
2718 for (i = regions.begin(); i != regions.end(); ++i) {
2728 /* region is moving up, move all regions on intermediate layers
2732 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2733 dest = (*i)->layer() - 1;
2740 /* region is moving down, move all regions on intermediate layers
2744 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2745 dest = (*i)->layer() + 1;
2755 newpair.second = dest;
2757 layerinfo.push_back (newpair);
2763 /* now reset the layers without holding the region lock */
2765 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2766 x->first->set_layer (x->second);
2769 region->set_layer (target_layer);
2771 /* now check all dependents, since we changed the layering */
2773 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2774 check_dependents (x->first, false);
2777 check_dependents (region, false);
2778 notify_layering_changed ();
2786 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2788 RegionList::iterator i;
2794 RegionLock rlock (const_cast<Playlist *> (this));
2796 for (i = regions.begin(); i != regions.end(); ++i) {
2798 if ((*i)->position() >= start) {
2804 if ((*i)->last_frame() > max_framepos - distance) {
2805 new_pos = max_framepos - (*i)->length();
2807 new_pos = (*i)->position() + distance;
2812 if ((*i)->position() > distance) {
2813 new_pos = (*i)->position() - distance;
2819 (*i)->set_position (new_pos, this);
2827 notify_length_changed ();
2833 Playlist::uses_source (boost::shared_ptr<const Source> src) const
2835 RegionLock rlock (const_cast<Playlist*> (this));
2837 for (set<boost::shared_ptr<Region> >::iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
2838 if ((*r)->uses_source (src)) {
2846 boost::shared_ptr<Region>
2847 Playlist::find_region (const ID& id) const
2849 RegionLock rlock (const_cast<Playlist*> (this));
2851 /* searches all regions currently in use by the playlist */
2853 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2854 if ((*i)->id() == id) {
2859 return boost::shared_ptr<Region> ();
2863 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2865 RegionLock rlock (const_cast<Playlist*> (this));
2868 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2877 boost::shared_ptr<Region>
2878 Playlist::region_by_id (const ID& id) const
2880 /* searches all regions ever added to this playlist */
2882 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2883 if ((*i)->id() == id) {
2887 return boost::shared_ptr<Region> ();
2891 Playlist::dump () const
2893 boost::shared_ptr<Region> r;
2895 cerr << "Playlist \"" << _name << "\" " << endl
2896 << regions.size() << " regions "
2899 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2901 cerr << " " << r->name() << " ["
2902 << r->start() << "+" << r->length()
2912 Playlist::set_frozen (bool yn)
2918 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2920 region->set_last_layer_op (++layer_op_counter);
2925 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2929 if (region->locked()) {
2936 RegionLock rlock (const_cast<Playlist*> (this));
2941 RegionList::iterator next;
2943 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2944 if ((*i) == region) {
2948 if (next != regions.end()) {
2950 if ((*next)->locked()) {
2956 if ((*next)->position() != region->last_frame() + 1) {
2957 /* they didn't used to touch, so after shuffle,
2958 just have them swap positions.
2960 new_pos = (*next)->position();
2962 /* they used to touch, so after shuffle,
2963 make sure they still do. put the earlier
2964 region where the later one will end after
2967 new_pos = region->position() + (*next)->length();
2970 (*next)->set_position (region->position(), this);
2971 region->set_position (new_pos, this);
2973 /* avoid a full sort */
2975 regions.erase (i); // removes the region from the list */
2977 regions.insert (next, region); // adds it back after next
2986 RegionList::iterator prev = regions.end();
2988 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2989 if ((*i) == region) {
2991 if (prev != regions.end()) {
2993 if ((*prev)->locked()) {
2998 if (region->position() != (*prev)->last_frame() + 1) {
2999 /* they didn't used to touch, so after shuffle,
3000 just have them swap positions.
3002 new_pos = region->position();
3004 /* they used to touch, so after shuffle,
3005 make sure they still do. put the earlier
3006 one where the later one will end after
3008 new_pos = (*prev)->position() + region->length();
3011 region->set_position ((*prev)->position(), this);
3012 (*prev)->set_position (new_pos, this);
3014 /* avoid a full sort */
3016 regions.erase (i); // remove region
3017 regions.insert (prev, region); // insert region before prev
3033 check_dependents (region, false);
3035 notify_contents_changed();
3041 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
3043 RegionLock rlock (const_cast<Playlist*> (this));
3045 if (regions.size() > 1) {
3053 Playlist::update_after_tempo_map_change ()
3055 RegionLock rlock (const_cast<Playlist*> (this));
3056 RegionList copy (regions.rlist());
3060 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
3061 (*i)->update_position_after_tempo_map_change ();
3068 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
3070 RegionLock rl (this, false);
3071 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3077 Playlist::set_explicit_relayering (bool e)
3079 if (e == false && _explicit_relayering == true) {
3081 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
3082 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
3083 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
3084 at this point would keep regions on the same layers.
3086 From then on in, it's just you and your towel.
3089 RegionLock rl (this);
3090 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3091 (*i)->set_last_layer_op ((*i)->layer ());
3095 _explicit_relayering = e;
3100 Playlist::has_region_at (framepos_t const p) const
3102 RegionLock (const_cast<Playlist *> (this));
3104 RegionList::const_iterator i = regions.begin ();
3105 while (i != regions.end() && !(*i)->covers (p)) {
3109 return (i != regions.end());
3112 /** Remove any region that uses a given source */
3114 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
3116 RegionLock rl (this);
3118 RegionList::iterator i = regions.begin();
3119 while (i != regions.end()) {
3120 RegionList::iterator j = i;
3123 if ((*i)->uses_source (s)) {
3124 remove_region_internal (*i);
3131 /** Look from a session frame time and find the start time of the next region
3132 * which is on the top layer of this playlist.
3133 * @param t Time to look from.
3134 * @return Position of next top-layered region, or max_framepos if there isn't one.
3137 Playlist::find_next_top_layer_position (framepos_t t) const
3139 RegionLock rlock (const_cast<Playlist *> (this));
3141 layer_t const top = top_layer ();
3143 RegionList copy = regions.rlist ();
3144 copy.sort (RegionSortByPosition ());
3146 for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3147 if ((*i)->position() >= t && (*i)->layer() == top) {
3148 return (*i)->position();
3152 return max_framepos;
3156 Playlist::combine (const RegionList& r, const std::string& name)
3159 uint32_t channels = 0;
3161 framepos_t earliest_position = max_framepos;
3162 vector<TwoRegions> old_and_new_regions;
3164 boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, name, true);
3166 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3167 earliest_position = min (earliest_position, (*i)->position());
3170 /* enable this so that we do not try to create xfades etc. as we add
3174 pl->in_partition = true;
3176 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3178 /* copy the region */
3180 boost::shared_ptr<Region> original_region = (*i);
3181 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
3183 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
3185 RegionFactory::add_compound_association (original_region, copied_region);
3187 /* make position relative to zero */
3189 pl->add_region (copied_region, original_region->position() - earliest_position);
3191 /* use the maximum number of channels for any region */
3193 channels = max (channels, original_region->n_channels());
3195 /* it will go above the layer of the highest existing region */
3197 layer = max (layer, original_region->layer());
3200 pl->in_partition = false;
3202 /* now create a new PlaylistSource for each channel in the new playlist */
3205 pair<framepos_t,framepos_t> extent = pl->get_extent();
3207 for (uint32_t chn = 0; chn < channels; ++chn) {
3208 sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, name, chn, 0, extent.second, false, false));
3211 /* now a new region using the list of sources */
3213 plist.add (Properties::start, 0);
3214 plist.add (Properties::length, extent.second);
3215 plist.add (Properties::name, name);
3216 plist.add (Properties::layer, layer+1);
3218 boost::shared_ptr<Region> compound_region = RegionFactory::create (sources, plist, true);
3220 /* add any dependent regions to the new playlist */
3222 copy_dependents (old_and_new_regions, pl);
3224 /* remove all the selected regions from the current playlist
3229 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3233 /* add the new region at the right location */
3235 add_region (compound_region, earliest_position);
3243 Playlist::uncombine (boost::shared_ptr<Region> target)
3245 // (1) check that its really a compound region
3247 boost::shared_ptr<PlaylistSource> pls;
3248 boost::shared_ptr<const Playlist> pl;
3249 vector<boost::shared_ptr<Region> > originals;
3251 if ((pls = boost::dynamic_pointer_cast<PlaylistSource>(target->source (0))) == 0) {
3255 pl = pls->playlist();
3257 framepos_t adjusted_start;
3258 framepos_t adjusted_end;
3260 /* the leftmost (earliest) edge of the compound region
3261 starts at zero in its source, or larger if it
3262 has been trimmed or content-scrolled.
3264 the rightmost (latest) edge of the compound region
3265 relative to its source is the starting point plus
3266 the length of the region.
3269 adjusted_start = target->start();
3270 adjusted_end = target->start() + target->length();
3272 // (2) get all the original regions
3274 const RegionList& rl (pl->region_list().rlist());
3275 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
3276 frameoffset_t move_offset = 0;
3278 for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
3280 boost::shared_ptr<Region> current (*i);
3283 RegionFactory::CompoundAssociations::iterator ca = cassocs.find (*i);
3285 if (ca == cassocs.end()) {
3289 boost::shared_ptr<Region> original (ca->second);
3290 bool modified_region;
3292 if (i == rl.begin()) {
3293 move_offset = (target->position() - original->position()) - target->start();
3296 /* check to see how the original region (in the
3297 * playlist before compounding occured) overlaps
3298 * with the new state of the compound region.
3301 original->clear_changes ();
3302 modified_region = false;
3304 switch (original->coverage (adjusted_start, adjusted_end)) {
3306 /* original region does not cover any part
3307 of the current state of the compound region
3311 case OverlapInternal:
3312 /* overlap is just a small piece inside the
3313 * original so trim both ends
3315 original->trim_to (adjusted_start, adjusted_end - adjusted_start, this);
3316 modified_region = true;
3319 case OverlapExternal:
3320 /* overlap fully covers original, so leave it
3326 /* overlap starts within but covers end,
3327 so trim the front of the region
3329 original->trim_front (adjusted_start, this);
3330 modified_region = true;
3334 /* overlap covers start but ends within, so
3335 * trim the end of the region.
3337 original->trim_end (adjusted_end, this);
3338 modified_region = true;
3343 /* fix the position to match any movement of the compound region.
3345 original->set_position (original->position() + move_offset, this);
3346 modified_region = true;
3349 if (modified_region) {
3350 _session.add_command (new StatefulDiffCommand (original));
3353 /* and add to the list of regions waiting to be
3357 originals.push_back (original);
3360 in_partition = true;
3363 // (3) remove the compound region
3365 remove_region (target);
3367 // (4) add the originals. This will reset their playlist reference back
3368 // to us, which means they are no longer considered owned by the RegionFactory
3370 for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
3371 add_region ((*i), (*i)->position());
3374 in_partition = false;
3379 Playlist::max_source_level () const
3381 RegionLock rlock (const_cast<Playlist *> (this));
3384 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3385 lvl = max (lvl, (*i)->max_source_level());
3393 Playlist::count_joined_regions () const
3395 RegionLock rlock (const_cast<Playlist *> (this));
3398 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3399 if ((*i)->max_source_level() > 0) {