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/transient_detector.h"
43 #include "ardour/session_playlists.h"
44 #include "ardour/source_factory.h"
49 using namespace ARDOUR;
53 namespace Properties {
54 PBD::PropertyDescriptor<bool> regions;
58 struct ShowMeTheList {
59 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
61 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
63 boost::shared_ptr<Playlist> playlist;
67 struct RegionSortByLayer {
68 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
69 return a->layer() < b->layer();
73 struct RegionSortByLayerWithPending {
74 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
76 double p = a->layer ();
77 if (a->pending_explicit_relayer()) {
81 double q = b->layer ();
82 if (b->pending_explicit_relayer()) {
90 struct RegionSortByPosition {
91 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
92 return a->position() < b->position();
96 struct RegionSortByLastLayerOp {
97 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
98 return a->last_layer_op() < b->last_layer_op();
103 Playlist::make_property_quarks ()
105 Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
106 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n",
107 Properties::regions.property_id));
110 RegionListProperty::RegionListProperty (Playlist& pl)
111 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
117 RegionListProperty::RegionListProperty (RegionListProperty const & p)
118 : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
119 , _playlist (p._playlist)
125 RegionListProperty::clone () const
127 return new RegionListProperty (*this);
131 RegionListProperty::create () const
133 return new RegionListProperty (_playlist);
137 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
139 /* All regions (even those which are deleted) have their state saved by other
140 code, so we can just store ID here.
143 node.add_property ("id", region->id().to_s ());
146 boost::shared_ptr<Region>
147 RegionListProperty::get_content_from_xml (XMLNode const & node) const
149 XMLProperty const * prop = node.property ("id");
152 PBD::ID id (prop->value ());
154 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
157 ret = RegionFactory::region_by_id (id);
163 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
164 : SessionObject(sess, nom)
169 first_set_state = false;
174 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
175 : SessionObject(sess, "unnamed playlist")
180 const XMLProperty* prop = node.property("type");
181 assert(!prop || DataType(prop->value()) == _type);
185 _name = "unnamed"; /* reset by set_state */
188 /* set state called by derived class */
191 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
192 : SessionObject(other->_session, namestr)
194 , _type(other->_type)
195 , _orig_diskstream_id (other->_orig_diskstream_id)
200 other->copy_regions (tmp);
204 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
205 add_region_internal( (*x), (*x)->position());
210 _splicing = other->_splicing;
211 _nudging = other->_nudging;
212 _edit_mode = other->_edit_mode;
215 first_set_state = false;
217 in_partition = false;
219 _read_data_count = 0;
220 _frozen = other->_frozen;
222 layer_op_counter = other->layer_op_counter;
223 freeze_length = other->freeze_length;
226 Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
227 : SessionObject(other->_session, str)
229 , _type(other->_type)
230 , _orig_diskstream_id (other->_orig_diskstream_id)
232 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
234 framepos_t end = start + cnt - 1;
240 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
242 boost::shared_ptr<Region> region;
243 boost::shared_ptr<Region> new_region;
244 frameoffset_t offset = 0;
245 framepos_t position = 0;
252 overlap = region->coverage (start, end);
258 case OverlapInternal:
259 offset = start - region->position();
266 position = region->position() - start;
267 len = end - region->position();
271 offset = start - region->position();
273 len = region->length() - offset;
276 case OverlapExternal:
278 position = region->position() - start;
279 len = region->length();
283 RegionFactory::region_name (new_name, region->name(), false);
287 plist.add (Properties::start, region->start() + offset);
288 plist.add (Properties::length, len);
289 plist.add (Properties::name, new_name);
290 plist.add (Properties::layer, region->layer());
292 new_region = RegionFactory::RegionFactory::create (region, plist);
294 add_region_internal (new_region, position);
298 first_set_state = false;
300 /* this constructor does NOT notify others (session) */
307 InUse (true); /* EMIT SIGNAL */
318 InUse (false); /* EMIT SIGNAL */
323 Playlist::copy_regions (RegionList& newlist) const
325 RegionLock rlock (const_cast<Playlist *> (this));
327 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
328 newlist.push_back (RegionFactory::RegionFactory::create (*i, true));
333 Playlist::init (bool hide)
335 add_property (regions);
336 _xml_node_name = X_("Playlist");
338 g_atomic_int_set (&block_notifications, 0);
339 g_atomic_int_set (&ignore_state_changes, 0);
340 pending_contents_change = false;
341 pending_length = false;
342 pending_layering = false;
343 first_set_state = true;
351 _edit_mode = Config->get_edit_mode();
353 in_partition = false;
355 _read_data_count = 0;
357 layer_op_counter = 0;
359 _explicit_relayering = false;
362 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
363 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
365 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
368 Playlist::~Playlist ()
370 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
373 RegionLock rl (this);
375 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
376 (*i)->set_playlist (boost::shared_ptr<Playlist>());
380 /* GoingAway must be emitted by derived classes */
384 Playlist::_set_sort_id ()
387 Playlists are given names like <track name>.<id>
388 or <track name>.<edit group name>.<id> where id
389 is an integer. We extract the id and sort by that.
392 size_t dot_position = _name.val().find_last_of(".");
394 if (dot_position == string::npos) {
397 string t = _name.val().substr(dot_position + 1);
400 _sort_id = boost::lexical_cast<int>(t);
403 catch (boost::bad_lexical_cast e) {
410 Playlist::set_name (const string& str)
412 /* in a typical situation, a playlist is being used
413 by one diskstream and also is referenced by the
414 Session. if there are more references than that,
415 then don't change the name.
422 bool ret = SessionObject::set_name(str);
429 /***********************************************************************
430 CHANGE NOTIFICATION HANDLING
432 Notifications must be delayed till the region_lock is released. This
433 is necessary because handlers for the signals may need to acquire
434 the lock (e.g. to read from the playlist).
435 ***********************************************************************/
438 Playlist::begin_undo ()
445 Playlist::end_undo ()
454 delay_notifications ();
455 g_atomic_int_inc (&ignore_state_changes);
458 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
460 Playlist::thaw (bool from_undo)
462 g_atomic_int_dec_and_test (&ignore_state_changes);
463 release_notifications (from_undo);
468 Playlist::delay_notifications ()
470 g_atomic_int_inc (&block_notifications);
471 freeze_length = _get_extent().second;
474 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
476 Playlist::release_notifications (bool from_undo)
478 if (g_atomic_int_dec_and_test (&block_notifications)) {
479 flush_notifications (from_undo);
484 Playlist::notify_contents_changed ()
486 if (holding_state ()) {
487 pending_contents_change = true;
489 pending_contents_change = false;
490 ContentsChanged(); /* EMIT SIGNAL */
495 Playlist::notify_layering_changed ()
497 if (holding_state ()) {
498 pending_layering = true;
500 pending_layering = false;
501 LayeringChanged(); /* EMIT SIGNAL */
506 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
508 if (holding_state ()) {
509 pending_removes.insert (r);
510 pending_contents_change = true;
511 pending_length = true;
513 /* this might not be true, but we have to act
514 as though it could be.
516 pending_length = false;
517 LengthChanged (); /* EMIT SIGNAL */
518 pending_contents_change = false;
519 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
520 ContentsChanged (); /* EMIT SIGNAL */
525 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
527 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
529 if (holding_state ()) {
531 pending_range_moves.push_back (move);
535 list< Evoral::RangeMove<framepos_t> > m;
537 RangesMoved (m, false);
543 Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r)
545 if (r->position() >= r->last_position()) {
546 /* trimmed shorter */
550 Evoral::Range<framepos_t> const extra (r->position(), r->last_position());
552 if (holding_state ()) {
554 pending_region_extensions.push_back (extra);
558 list<Evoral::Range<framepos_t> > r;
566 Playlist::notify_region_end_trimmed (boost::shared_ptr<Region> r)
568 if (r->length() < r->last_length()) {
569 /* trimmed shorter */
572 Evoral::Range<framepos_t> const extra (r->position() + r->last_length(), r->position() + r->length());
574 if (holding_state ()) {
576 pending_region_extensions.push_back (extra);
580 list<Evoral::Range<framepos_t> > r;
588 Playlist::notify_region_added (boost::shared_ptr<Region> r)
590 /* the length change might not be true, but we have to act
591 as though it could be.
594 if (holding_state()) {
595 pending_adds.insert (r);
596 pending_contents_change = true;
597 pending_length = true;
600 pending_length = false;
601 LengthChanged (); /* EMIT SIGNAL */
602 pending_contents_change = false;
603 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
604 ContentsChanged (); /* EMIT SIGNAL */
609 Playlist::notify_length_changed ()
611 if (holding_state ()) {
612 pending_length = true;
614 pending_length = false;
615 LengthChanged(); /* EMIT SIGNAL */
616 pending_contents_change = false;
617 ContentsChanged (); /* EMIT SIGNAL */
621 /** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
623 Playlist::flush_notifications (bool from_undo)
625 set<boost::shared_ptr<Region> > dependent_checks_needed;
626 set<boost::shared_ptr<Region> >::iterator s;
627 uint32_t regions_changed = false;
628 bool check_length = false;
629 framecnt_t old_length = 0;
637 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
638 regions_changed = true;
639 if (!pending_length) {
640 old_length = _get_extent ().second;
645 /* we have no idea what order the regions ended up in pending
646 bounds (it could be based on selection order, for example).
647 so, to preserve layering in the "most recently moved is higher"
648 model, sort them by existing layer, then timestamp them.
651 // RegionSortByLayer cmp;
652 // pending_bounds.sort (cmp);
654 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
655 if (_session.config.get_layer_model() == MoveAddHigher) {
656 timestamp_layer_op (*r);
658 dependent_checks_needed.insert (*r);
661 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
662 remove_dependents (*s);
663 // cerr << _name << " sends RegionRemoved\n";
664 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
667 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
668 // cerr << _name << " sends RegionAdded\n";
669 /* don't emit RegionAdded signal until relayering is done,
670 so that the region is fully setup by the time
671 anyone hear's that its been added
673 dependent_checks_needed.insert (*s);
677 if (old_length != _get_extent().second) {
678 pending_length = true;
679 // cerr << _name << " length has changed\n";
683 if (pending_length || (freeze_length != _get_extent().second)) {
684 pending_length = false;
685 // cerr << _name << " sends LengthChanged\n";
686 LengthChanged(); /* EMIT SIGNAL */
689 if (regions_changed || pending_contents_change) {
693 pending_contents_change = false;
694 // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
695 ContentsChanged (); /* EMIT SIGNAL */
696 // cerr << _name << "done contents change @ " << get_microseconds() << endl;
699 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
700 (*s)->clear_changes ();
701 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
704 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
705 check_dependents (*s, false);
708 if (!pending_range_moves.empty ()) {
709 RangesMoved (pending_range_moves, from_undo);
712 if (!pending_region_extensions.empty ()) {
713 RegionsExtended (pending_region_extensions);
722 Playlist::clear_pending ()
724 pending_adds.clear ();
725 pending_removes.clear ();
726 pending_bounds.clear ();
727 pending_range_moves.clear ();
728 pending_region_extensions.clear ();
729 pending_contents_change = false;
730 pending_length = false;
733 /*************************************************************
735 *************************************************************/
738 Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
740 RegionLock rlock (this);
741 times = fabs (times);
743 int itimes = (int) floor (times);
745 framepos_t pos = position;
747 if (times == 1 && auto_partition){
748 partition(pos - 1, (pos + region->length()), true);
752 add_region_internal (region, pos);
753 pos += region->length();
758 /* note that itimes can be zero if we being asked to just
759 insert a single fraction of the region.
762 for (int i = 0; i < itimes; ++i) {
763 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
764 add_region_internal (copy, pos);
765 pos += region->length();
768 framecnt_t length = 0;
770 if (floor (times) != times) {
771 length = (framecnt_t) floor (region->length() * (times - floor (times)));
773 RegionFactory::region_name (name, region->name(), false);
778 plist.add (Properties::start, region->start());
779 plist.add (Properties::length, length);
780 plist.add (Properties::name, name);
781 plist.add (Properties::layer, region->layer());
783 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
784 add_region_internal (sub, pos);
788 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
792 Playlist::set_region_ownership ()
794 RegionLock rl (this);
795 RegionList::iterator i;
796 boost::weak_ptr<Playlist> pl (shared_from_this());
798 for (i = regions.begin(); i != regions.end(); ++i) {
799 (*i)->set_playlist (pl);
804 Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
806 if (region->data_type() != _type){
810 RegionSortByPosition cmp;
812 framecnt_t old_length = 0;
814 if (!holding_state()) {
815 old_length = _get_extent().second;
818 if (!first_set_state) {
819 boost::shared_ptr<Playlist> foo (shared_from_this());
820 region->set_playlist (boost::weak_ptr<Playlist>(foo));
823 region->set_position (position, this);
825 timestamp_layer_op (region);
827 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
828 all_regions.insert (region);
830 possibly_splice_unlocked (position, region->length(), region);
832 if (!holding_state ()) {
833 /* layers get assigned from XML state, and are not reset during undo/redo */
837 /* we need to notify the existence of new region before checking dependents. Ick. */
839 notify_region_added (region);
841 if (!holding_state ()) {
843 check_dependents (region, false);
845 if (old_length != _get_extent().second) {
846 notify_length_changed ();
850 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
856 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
858 RegionLock rlock (this);
860 bool old_sp = _splicing;
863 remove_region_internal (old);
864 add_region_internal (newr, pos);
868 possibly_splice_unlocked (pos, old->length() - newr->length());
872 Playlist::remove_region (boost::shared_ptr<Region> region)
874 RegionLock rlock (this);
875 remove_region_internal (region);
879 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
881 RegionList::iterator i;
882 framecnt_t old_length = 0;
885 if (!holding_state()) {
886 old_length = _get_extent().second;
891 region->set_playlist (boost::weak_ptr<Playlist>());
894 /* XXX should probably freeze here .... */
896 for (i = regions.begin(); i != regions.end(); ++i) {
899 framepos_t pos = (*i)->position();
900 framecnt_t distance = (*i)->length();
904 possibly_splice_unlocked (pos, -distance);
906 if (!holding_state ()) {
908 remove_dependents (region);
910 if (old_length != _get_extent().second) {
911 notify_length_changed ();
915 notify_region_removed (region);
925 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
927 if (Config->get_use_overlap_equivalency()) {
928 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
929 if ((*i)->overlap_equivalent (other)) {
930 results.push_back ((*i));
934 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
935 if ((*i)->equivalent (other)) {
936 results.push_back ((*i));
943 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
945 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
947 if ((*i) && (*i)->region_list_equivalent (other)) {
948 results.push_back (*i);
954 Playlist::partition (framepos_t start, framepos_t end, bool cut)
958 partition_internal (start, end, cut, thawlist);
960 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
961 (*i)->resume_property_changes ();
966 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
968 RegionList new_regions;
971 RegionLock rlock (this);
973 boost::shared_ptr<Region> region;
974 boost::shared_ptr<Region> current;
976 RegionList::iterator tmp;
978 framepos_t pos1, pos2, pos3, pos4;
982 /* need to work from a copy, because otherwise the regions we add during the process
983 get operated on as well.
986 RegionList copy = regions.rlist();
988 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
995 if (current->first_frame() >= start && current->last_frame() < end) {
998 remove_region_internal (current);
1004 /* coverage will return OverlapStart if the start coincides
1005 with the end point. we do not partition such a region,
1006 so catch this special case.
1009 if (current->first_frame() >= end) {
1013 if ((overlap = current->coverage (start, end)) == OverlapNone) {
1017 pos1 = current->position();
1020 pos4 = current->last_frame();
1022 if (overlap == OverlapInternal) {
1023 /* split: we need 3 new regions, the front, middle and end.
1024 cut: we need 2 regions, the front and end.
1029 ---------------*************************------------
1032 ---------------*****++++++++++++++++====------------
1034 ---------------*****----------------====------------
1039 /* "middle" ++++++ */
1041 RegionFactory::region_name (new_name, current->name(), false);
1045 plist.add (Properties::start, current->start() + (pos2 - pos1));
1046 plist.add (Properties::length, pos3 - pos2);
1047 plist.add (Properties::name, new_name);
1048 plist.add (Properties::layer, regions.size());
1049 plist.add (Properties::automatic, true);
1050 plist.add (Properties::left_of_split, true);
1051 plist.add (Properties::right_of_split, true);
1053 region = RegionFactory::create (current, plist);
1054 add_region_internal (region, start);
1055 new_regions.push_back (region);
1060 RegionFactory::region_name (new_name, current->name(), false);
1064 plist.add (Properties::start, current->start() + (pos3 - pos1));
1065 plist.add (Properties::length, pos4 - pos3);
1066 plist.add (Properties::name, new_name);
1067 plist.add (Properties::layer, regions.size());
1068 plist.add (Properties::automatic, true);
1069 plist.add (Properties::right_of_split, true);
1071 region = RegionFactory::create (current, plist);
1073 add_region_internal (region, end);
1074 new_regions.push_back (region);
1078 current->suspend_property_changes ();
1079 thawlist.push_back (current);
1080 current->cut_end (pos2 - 1, this);
1082 } else if (overlap == OverlapEnd) {
1086 ---------------*************************------------
1089 ---------------**************+++++++++++------------
1091 ---------------**************-----------------------
1098 RegionFactory::region_name (new_name, current->name(), false);
1102 plist.add (Properties::start, current->start() + (pos2 - pos1));
1103 plist.add (Properties::length, pos4 - pos2);
1104 plist.add (Properties::name, new_name);
1105 plist.add (Properties::layer, regions.size());
1106 plist.add (Properties::automatic, true);
1107 plist.add (Properties::left_of_split, true);
1109 region = RegionFactory::create (current, plist);
1111 add_region_internal (region, start);
1112 new_regions.push_back (region);
1117 current->suspend_property_changes ();
1118 thawlist.push_back (current);
1119 current->cut_end (pos2 - 1, this);
1121 } else if (overlap == OverlapStart) {
1123 /* split: we need 2 regions: the front and the end.
1124 cut: just trim current to skip the cut area
1129 ---------------*************************------------
1133 ---------------****+++++++++++++++++++++------------
1135 -------------------*********************------------
1141 RegionFactory::region_name (new_name, current->name(), false);
1145 plist.add (Properties::start, current->start());
1146 plist.add (Properties::length, pos3 - pos1);
1147 plist.add (Properties::name, new_name);
1148 plist.add (Properties::layer, regions.size());
1149 plist.add (Properties::automatic, true);
1150 plist.add (Properties::right_of_split, true);
1152 region = RegionFactory::create (current, plist);
1154 add_region_internal (region, pos1);
1155 new_regions.push_back (region);
1160 current->suspend_property_changes ();
1161 thawlist.push_back (current);
1162 current->trim_front (pos3, this);
1163 } else if (overlap == OverlapExternal) {
1165 /* split: no split required.
1166 cut: remove the region.
1171 ---------------*************************------------
1175 ---------------*************************------------
1177 ----------------------------------------------------
1182 remove_region_internal (current);
1185 new_regions.push_back (current);
1189 in_partition = false;
1192 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1193 check_dependents (*i, false);
1197 boost::shared_ptr<Playlist>
1198 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1200 boost::shared_ptr<Playlist> ret;
1201 boost::shared_ptr<Playlist> pl;
1204 if (ranges.empty()) {
1205 return boost::shared_ptr<Playlist>();
1208 start = ranges.front().start;
1210 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1212 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1214 if (i == ranges.begin()) {
1218 /* paste the next section into the nascent playlist,
1219 offset to reflect the start of the first range we
1223 ret->paste (pl, (*i).start - start, 1.0f);
1230 boost::shared_ptr<Playlist>
1231 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1233 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1234 return cut_copy (pmf, ranges, result_is_hidden);
1237 boost::shared_ptr<Playlist>
1238 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1240 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1241 return cut_copy (pmf, ranges, result_is_hidden);
1244 boost::shared_ptr<Playlist>
1245 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1247 boost::shared_ptr<Playlist> the_copy;
1248 RegionList thawlist;
1251 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1252 string new_name = _name;
1256 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1257 return boost::shared_ptr<Playlist>();
1260 partition_internal (start, start+cnt-1, true, thawlist);
1262 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1263 (*i)->resume_property_changes();
1269 boost::shared_ptr<Playlist>
1270 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1274 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1275 string new_name = _name;
1279 cnt = min (_get_extent().second - start, cnt);
1280 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1284 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1286 times = fabs (times);
1289 RegionLock rl1 (this);
1290 RegionLock rl2 (other.get());
1292 framecnt_t const old_length = _get_extent().second;
1294 int itimes = (int) floor (times);
1295 framepos_t pos = position;
1296 framecnt_t const shift = other->_get_extent().second;
1297 layer_t top_layer = regions.size();
1300 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1301 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1303 /* put these new regions on top of all existing ones, but preserve
1304 the ordering they had in the original playlist.
1307 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1308 add_region_internal (copy_of_region, (*i)->position() + pos);
1314 /* XXX shall we handle fractional cases at some point? */
1316 if (old_length != _get_extent().second) {
1317 notify_length_changed ();
1328 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1330 times = fabs (times);
1332 RegionLock rl (this);
1333 int itimes = (int) floor (times);
1334 framepos_t pos = position + 1;
1337 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1338 add_region_internal (copy, pos);
1339 pos += region->length();
1342 if (floor (times) != times) {
1343 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1345 RegionFactory::region_name (name, region->name(), false);
1350 plist.add (Properties::start, region->start());
1351 plist.add (Properties::length, length);
1352 plist.add (Properties::name, name);
1354 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1355 add_region_internal (sub, pos);
1361 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1363 RegionLock rlock (this);
1364 RegionList copy (regions.rlist());
1367 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1369 if ((*r)->last_frame() < at) {
1374 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1375 /* intersected region */
1376 if (!move_intersected) {
1381 /* do not move regions glued to music time - that
1382 has to be done separately.
1385 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1386 fixup.push_back (*r);
1390 (*r)->set_position ((*r)->position() + distance, this);
1393 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1394 (*r)->recompute_position_from_lock_style ();
1399 Playlist::split (framepos_t at)
1401 RegionLock rlock (this);
1402 RegionList copy (regions.rlist());
1404 /* use a copy since this operation can modify the region list
1407 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1408 _split_region (*r, at);
1413 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1415 RegionLock rl (this);
1416 _split_region (region, playlist_position);
1420 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1422 if (!region->covers (playlist_position)) {
1426 if (region->position() == playlist_position ||
1427 region->last_frame() == playlist_position) {
1431 boost::shared_ptr<Region> left;
1432 boost::shared_ptr<Region> right;
1433 frameoffset_t before;
1434 frameoffset_t after;
1438 /* split doesn't change anything about length, so don't try to splice */
1440 bool old_sp = _splicing;
1443 before = playlist_position - region->position();
1444 after = region->length() - before;
1446 RegionFactory::region_name (before_name, region->name(), false);
1451 plist.add (Properties::position, region->position ());
1452 plist.add (Properties::length, before);
1453 plist.add (Properties::name, before_name);
1454 plist.add (Properties::left_of_split, true);
1456 /* note: we must use the version of ::create with an offset here,
1457 since it supplies that offset to the Region constructor, which
1458 is necessary to get audio region gain envelopes right.
1460 left = RegionFactory::create (region, 0, plist);
1463 RegionFactory::region_name (after_name, region->name(), false);
1468 plist.add (Properties::position, region->position() + before);
1469 plist.add (Properties::length, after);
1470 plist.add (Properties::name, after_name);
1471 plist.add (Properties::right_of_split, true);
1473 /* same note as above */
1474 right = RegionFactory::create (region, before, plist);
1477 add_region_internal (left, region->position());
1478 add_region_internal (right, region->position() + before);
1480 uint64_t orig_layer_op = region->last_layer_op();
1481 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1482 if ((*i)->last_layer_op() > orig_layer_op) {
1483 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1487 left->set_last_layer_op ( orig_layer_op );
1488 right->set_last_layer_op ( orig_layer_op + 1);
1492 finalize_split_region (region, left, right);
1494 remove_region_internal (region);
1500 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1502 if (_splicing || in_set_state) {
1503 /* don't respond to splicing moves or state setting */
1507 if (_edit_mode == Splice) {
1508 splice_locked (at, distance, exclude);
1513 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1515 if (_splicing || in_set_state) {
1516 /* don't respond to splicing moves or state setting */
1520 if (_edit_mode == Splice) {
1521 splice_unlocked (at, distance, exclude);
1526 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1529 RegionLock rl (this);
1530 core_splice (at, distance, exclude);
1535 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1537 core_splice (at, distance, exclude);
1541 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1545 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1547 if (exclude && (*i) == exclude) {
1551 if ((*i)->position() >= at) {
1552 framepos_t new_pos = (*i)->position() + distance;
1555 } else if (new_pos >= max_framepos - (*i)->length()) {
1556 new_pos = max_framepos - (*i)->length();
1559 (*i)->set_position (new_pos, this);
1565 notify_length_changed ();
1569 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1571 if (in_set_state || _splicing || _nudging || _shuffling) {
1575 if (what_changed.contains (Properties::position)) {
1577 /* remove it from the list then add it back in
1578 the right place again.
1581 RegionSortByPosition cmp;
1583 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1585 if (i == regions.end()) {
1586 /* the region bounds are being modified but its not currently
1587 in the region list. we will use its bounds correctly when/if
1594 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1597 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1599 frameoffset_t delta = 0;
1601 if (what_changed.contains (Properties::position)) {
1602 delta = region->position() - region->last_position();
1605 if (what_changed.contains (Properties::length)) {
1606 delta += region->length() - region->last_length();
1610 possibly_splice (region->last_position() + region->last_length(), delta, region);
1613 if (holding_state ()) {
1614 pending_bounds.push_back (region);
1616 if (_session.config.get_layer_model() == MoveAddHigher) {
1617 /* it moved or changed length, so change the timestamp */
1618 timestamp_layer_op (region);
1621 notify_length_changed ();
1623 check_dependents (region, false);
1629 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1631 boost::shared_ptr<Region> region (weak_region.lock());
1637 /* this makes a virtual call to the right kind of playlist ... */
1639 region_changed (what_changed, region);
1643 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1645 PropertyChange our_interests;
1646 PropertyChange bounds;
1647 PropertyChange pos_and_length;
1650 if (in_set_state || in_flush) {
1654 our_interests.add (Properties::muted);
1655 our_interests.add (Properties::layer);
1656 our_interests.add (Properties::opaque);
1658 bounds.add (Properties::start);
1659 bounds.add (Properties::position);
1660 bounds.add (Properties::length);
1662 pos_and_length.add (Properties::position);
1663 pos_and_length.add (Properties::length);
1665 if (what_changed.contains (bounds)) {
1666 region_bounds_changed (what_changed, region);
1667 save = !(_splicing || _nudging);
1670 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1671 check_dependents (region, false);
1674 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1675 notify_region_moved (region);
1676 } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1677 notify_region_end_trimmed (region);
1678 } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1679 notify_region_start_trimmed (region);
1682 /* don't notify about layer changes, since we are the only object that can initiate
1683 them, and we notify in ::relayer()
1686 if (what_changed.contains (our_interests)) {
1694 Playlist::drop_regions ()
1696 RegionLock rl (this);
1698 all_regions.clear ();
1702 Playlist::sync_all_regions_with_regions ()
1704 RegionLock rl (this);
1706 all_regions.clear ();
1708 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1709 all_regions.insert (*i);
1714 Playlist::clear (bool with_signals)
1717 RegionLock rl (this);
1719 region_state_changed_connections.drop_connections ();
1721 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1722 pending_removes.insert (*i);
1727 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1728 remove_dependents (*s);
1734 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1735 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1738 pending_removes.clear ();
1739 pending_length = false;
1741 pending_contents_change = false;
1747 /***********************************************************************
1749 **********************************************************************/
1751 Playlist::RegionList *
1752 Playlist::regions_at (framepos_t frame)
1755 RegionLock rlock (this);
1756 return find_regions_at (frame);
1760 Playlist::count_regions_at (framepos_t frame) const
1762 RegionLock rlock (const_cast<Playlist*>(this));
1765 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1766 if ((*i)->covers (frame)) {
1774 boost::shared_ptr<Region>
1775 Playlist::top_region_at (framepos_t frame)
1778 RegionLock rlock (this);
1779 RegionList *rlist = find_regions_at (frame);
1780 boost::shared_ptr<Region> region;
1782 if (rlist->size()) {
1783 RegionSortByLayer cmp;
1785 region = rlist->back();
1792 boost::shared_ptr<Region>
1793 Playlist::top_unmuted_region_at (framepos_t frame)
1796 RegionLock rlock (this);
1797 RegionList *rlist = find_regions_at (frame);
1799 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1801 RegionList::iterator tmp = i;
1804 if ((*i)->muted()) {
1811 boost::shared_ptr<Region> region;
1813 if (rlist->size()) {
1814 RegionSortByLayer cmp;
1816 region = rlist->back();
1823 Playlist::RegionList*
1824 Playlist::regions_to_read (framepos_t start, framepos_t end)
1826 /* Caller must hold lock */
1828 RegionList covering;
1829 set<framepos_t> to_check;
1830 set<boost::shared_ptr<Region> > unique;
1832 to_check.insert (start);
1833 to_check.insert (end);
1835 DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1837 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1839 /* find all/any regions that span start+end */
1841 switch ((*i)->coverage (start, end)) {
1845 case OverlapInternal:
1846 covering.push_back (*i);
1847 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1851 to_check.insert ((*i)->position());
1852 if ((*i)->position() != 0) {
1853 to_check.insert ((*i)->position()-1);
1855 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1856 covering.push_back (*i);
1860 to_check.insert ((*i)->last_frame());
1861 to_check.insert ((*i)->last_frame()+1);
1862 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1863 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1864 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1865 covering.push_back (*i);
1868 case OverlapExternal:
1869 covering.push_back (*i);
1870 to_check.insert ((*i)->position());
1871 if ((*i)->position() != 0) {
1872 to_check.insert ((*i)->position()-1);
1874 to_check.insert ((*i)->last_frame());
1875 to_check.insert ((*i)->last_frame()+1);
1876 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1877 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1878 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1882 /* don't go too far */
1884 if ((*i)->position() > end) {
1889 RegionList* rlist = new RegionList;
1891 /* find all the regions that cover each position .... */
1893 if (covering.size() == 1) {
1895 rlist->push_back (covering.front());
1896 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1901 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1905 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1907 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1909 if ((*x)->covers (*t)) {
1910 here.push_back (*x);
1911 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1915 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1922 RegionSortByLayer cmp;
1925 /* ... and get the top/transparent regions at "here" */
1927 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1931 if ((*c)->opaque()) {
1933 /* the other regions at this position are hidden by this one */
1934 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1941 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1942 rlist->push_back (*s);
1945 if (rlist->size() > 1) {
1946 /* now sort by time order */
1948 RegionSortByPosition cmp;
1953 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1958 Playlist::RegionList *
1959 Playlist::find_regions_at (framepos_t frame)
1961 /* Caller must hold lock */
1963 RegionList *rlist = new RegionList;
1965 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1966 if ((*i)->covers (frame)) {
1967 rlist->push_back (*i);
1974 Playlist::RegionList *
1975 Playlist::regions_touched (framepos_t start, framepos_t end)
1977 RegionLock rlock (this);
1978 RegionList *rlist = new RegionList;
1980 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1981 if ((*i)->coverage (start, end) != OverlapNone) {
1982 rlist->push_back (*i);
1990 Playlist::find_next_transient (framepos_t from, int dir)
1992 RegionLock rlock (this);
1993 AnalysisFeatureList points;
1994 AnalysisFeatureList these_points;
1996 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1998 if ((*i)->last_frame() < from) {
2002 if ((*i)->first_frame() > from) {
2007 (*i)->get_transients (these_points);
2009 /* add first frame, just, err, because */
2011 these_points.push_back ((*i)->first_frame());
2013 points.insert (points.end(), these_points.begin(), these_points.end());
2014 these_points.clear ();
2017 if (points.empty()) {
2021 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
2022 bool reached = false;
2025 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
2030 if (reached && (*x) > from) {
2035 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2040 if (reached && (*x) < from) {
2049 boost::shared_ptr<Region>
2050 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
2052 RegionLock rlock (this);
2053 boost::shared_ptr<Region> ret;
2054 framepos_t closest = max_framepos;
2056 bool end_iter = false;
2058 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2062 frameoffset_t distance;
2063 boost::shared_ptr<Region> r = (*i);
2068 pos = r->first_frame ();
2071 pos = r->last_frame ();
2074 pos = r->sync_position ();
2079 case 1: /* forwards */
2082 if ((distance = pos - frame) < closest) {
2091 default: /* backwards */
2094 if ((distance = frame - pos) < closest) {
2111 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2113 RegionLock rlock (this);
2115 framepos_t closest = max_framepos;
2116 framepos_t ret = -1;
2120 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2122 boost::shared_ptr<Region> r = (*i);
2123 frameoffset_t distance;
2125 if (r->first_frame() > frame) {
2127 distance = r->first_frame() - frame;
2129 if (distance < closest) {
2130 ret = r->first_frame();
2135 if (r->last_frame () > frame) {
2137 distance = r->last_frame () - frame;
2139 if (distance < closest) {
2140 ret = r->last_frame ();
2148 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2150 boost::shared_ptr<Region> r = (*i);
2151 frameoffset_t distance;
2153 if (r->last_frame() < frame) {
2155 distance = frame - r->last_frame();
2157 if (distance < closest) {
2158 ret = r->last_frame();
2163 if (r->first_frame() < frame) {
2165 distance = frame - r->first_frame();
2167 if (distance < closest) {
2168 ret = r->first_frame();
2179 /***********************************************************************/
2185 Playlist::mark_session_dirty ()
2187 if (!in_set_state && !holding_state ()) {
2188 _session.set_dirty();
2193 Playlist::rdiff (vector<Command*>& cmds) const
2195 RegionLock rlock (const_cast<Playlist *> (this));
2196 Stateful::rdiff (cmds);
2200 Playlist::clear_owned_changes ()
2202 RegionLock rlock (this);
2203 Stateful::clear_owned_changes ();
2207 Playlist::update (const RegionListProperty::ChangeRecord& change)
2209 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2210 name(), change.added.size(), change.removed.size()));
2213 /* add the added regions */
2214 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2215 add_region ((*i), (*i)->position());
2217 /* remove the removed regions */
2218 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2226 Playlist::load_nested_sources (const XMLNode& node)
2229 XMLNodeConstIterator niter;
2231 nlist = node.children();
2233 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2234 if ((*niter)->name() == "Source") {
2236 SourceFactory::create (_session, **niter, true);
2238 catch (failed_constructor& err) {
2239 error << string_compose (_("Cannot reconstruct nested source for playlist %1"), name()) << endmsg;
2246 Playlist::set_state (const XMLNode& node, int version)
2250 XMLNodeConstIterator niter;
2251 XMLPropertyList plist;
2252 XMLPropertyConstIterator piter;
2254 boost::shared_ptr<Region> region;
2259 if (node.name() != "Playlist") {
2266 plist = node.properties();
2268 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2272 if (prop->name() == X_("name")) {
2273 _name = prop->value();
2275 } else if (prop->name() == X_("id")) {
2276 _id = prop->value();
2277 } else if (prop->name() == X_("orig_diskstream_id")) {
2278 _orig_diskstream_id = prop->value ();
2279 } else if (prop->name() == X_("frozen")) {
2280 _frozen = string_is_affirmative (prop->value());
2281 } else if (prop->name() == X_("combine-ops")) {
2282 _combine_ops = atoi (prop->value());
2288 nlist = node.children();
2290 /* find the "Nested" node, if any, and recreate the PlaylistSources
2294 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2297 if (child->name() == "Nested") {
2298 load_nested_sources (*child);
2303 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2307 if (child->name() == "Region") {
2309 if ((prop = child->property ("id")) == 0) {
2310 error << _("region state node has no ID, ignored") << endmsg;
2314 ID id = prop->value ();
2316 if ((region = region_by_id (id))) {
2318 region->suspend_property_changes ();
2320 if (region->set_state (*child, version)) {
2321 region->resume_property_changes ();
2325 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2326 region->suspend_property_changes ();
2328 error << _("Playlist: cannot create region from XML") << endmsg;
2333 add_region (region, region->position(), 1.0);
2335 // So that layer_op ordering doesn't get screwed up
2336 region->set_last_layer_op( region->layer());
2337 region->resume_property_changes ();
2341 /* update dependents, which was not done during add_region_internal
2342 due to in_set_state being true
2345 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2346 check_dependents (*r, false);
2350 notify_contents_changed ();
2353 first_set_state = false;
2358 Playlist::get_state()
2360 return state (true);
2364 Playlist::get_template()
2366 return state (false);
2369 /** @param full_state true to include regions in the returned state, otherwise false.
2372 Playlist::state (bool full_state)
2374 XMLNode *node = new XMLNode (X_("Playlist"));
2377 node->add_property (X_("id"), id().to_s());
2378 node->add_property (X_("name"), _name);
2379 node->add_property (X_("type"), _type.to_string());
2381 _orig_diskstream_id.print (buf, sizeof (buf));
2382 node->add_property (X_("orig_diskstream_id"), buf);
2383 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2386 RegionLock rlock (this, false);
2387 XMLNode* nested_node = 0;
2389 snprintf (buf, sizeof (buf), "%u", _combine_ops);
2390 node->add_property ("combine-ops", buf);
2392 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2393 if ((*i)->max_source_level() > 0) {
2396 nested_node = new XMLNode (X_("Nested"));
2399 /* region is compound - get its playlist and
2400 store that before we list the region that
2404 const SourceList& sl ((*i)->sources());
2406 for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
2407 nested_node->add_child_nocopy ((*s)->get_state ());
2413 node->add_child_nocopy (*nested_node);
2416 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2417 node->add_child_nocopy ((*i)->get_state());
2422 node->add_child_copy (*_extra_xml);
2429 Playlist::empty() const
2431 RegionLock rlock (const_cast<Playlist *>(this), false);
2432 return regions.empty();
2436 Playlist::n_regions() const
2438 RegionLock rlock (const_cast<Playlist *>(this), false);
2439 return regions.size();
2442 pair<framepos_t, framepos_t>
2443 Playlist::get_extent () const
2445 RegionLock rlock (const_cast<Playlist *>(this), false);
2446 return _get_extent ();
2449 pair<framepos_t, framepos_t>
2450 Playlist::_get_extent () const
2452 pair<framepos_t, framepos_t> ext (max_framepos, 0);
2454 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2455 pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2456 if (e.first < ext.first) {
2457 ext.first = e.first;
2459 if (e.second > ext.second) {
2460 ext.second = e.second;
2468 Playlist::bump_name (string name, Session &session)
2470 string newname = name;
2473 newname = bump_name_once (newname, '.');
2474 } while (session.playlists->by_name (newname)!=NULL);
2481 Playlist::top_layer() const
2483 RegionLock rlock (const_cast<Playlist *> (this));
2486 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2487 top = max (top, (*i)->layer());
2493 Playlist::set_edit_mode (EditMode mode)
2498 /********************
2500 ********************/
2503 Playlist::relayer ()
2505 /* never compute layers when changing state for undo/redo or setting from XML */
2507 if (in_update || in_set_state) {
2511 bool changed = false;
2513 /* Build up a new list of regions on each layer, stored in a set of lists
2514 each of which represent some period of time on some layer. The idea
2515 is to avoid having to search the entire region list to establish whether
2516 each region overlaps another */
2518 /* how many pieces to divide this playlist's time up into */
2519 int const divisions = 512;
2521 /* find the start and end positions of the regions on this playlist */
2522 framepos_t start = INT64_MAX;
2524 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2525 start = min (start, (*i)->position());
2526 end = max (end, (*i)->position() + (*i)->length());
2529 /* hence the size of each time division */
2530 double const division_size = (end - start) / double (divisions);
2532 vector<vector<RegionList> > layers;
2533 layers.push_back (vector<RegionList> (divisions));
2535 /* we want to go through regions from desired lowest to desired highest layer,
2536 which depends on the layer model
2539 RegionList copy = regions.rlist();
2541 /* sort according to the model and the layering mode that we're in */
2543 if (_explicit_relayering) {
2545 copy.sort (RegionSortByLayerWithPending ());
2547 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2549 copy.sort (RegionSortByLastLayerOp ());
2554 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2556 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2557 (*i)->set_pending_explicit_relayer (false);
2559 /* find the time divisions that this region covers; if there are no regions on the list,
2560 division_size will equal 0 and in this case we'll just say that
2561 start_division = end_division = 0.
2563 int start_division = 0;
2564 int end_division = 0;
2566 if (division_size > 0) {
2567 start_division = floor ( ((*i)->position() - start) / division_size);
2568 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2569 if (end_division == divisions) {
2574 assert (divisions == 0 || end_division < divisions);
2576 /* find the lowest layer that this region can go on */
2577 size_t j = layers.size();
2579 /* try layer j - 1; it can go on if it overlaps no other region
2580 that is already on that layer
2583 bool overlap = false;
2584 for (int k = start_division; k <= end_division; ++k) {
2585 RegionList::iterator l = layers[j-1][k].begin ();
2586 while (l != layers[j-1][k].end()) {
2587 if ((*l)->overlap_equivalent (*i)) {
2600 /* overlap, so we must use layer j */
2607 if (j == layers.size()) {
2608 /* we need a new layer for this region */
2609 layers.push_back (vector<RegionList> (divisions));
2612 /* put a reference to this region in each of the divisions that it exists in */
2613 for (int k = start_division; k <= end_division; ++k) {
2614 layers[j][k].push_back (*i);
2617 if ((*i)->layer() != j) {
2621 (*i)->set_layer (j);
2625 notify_layering_changed ();
2629 /* XXX these layer functions are all deprecated */
2632 Playlist::raise_region (boost::shared_ptr<Region> region)
2634 uint32_t top = regions.size() - 1;
2635 layer_t target = region->layer() + 1U;
2637 if (target >= top) {
2638 /* its already at the effective top */
2642 move_region_to_layer (target, region, 1);
2646 Playlist::lower_region (boost::shared_ptr<Region> region)
2648 if (region->layer() == 0) {
2649 /* its already at the bottom */
2653 layer_t target = region->layer() - 1U;
2655 move_region_to_layer (target, region, -1);
2659 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2661 /* does nothing useful if layering mode is later=higher */
2662 switch (_session.config.get_layer_model()) {
2669 layer_t top = regions.size() - 1;
2671 if (region->layer() >= top) {
2672 /* already on the top */
2676 move_region_to_layer (top, region, 1);
2677 /* mark the region's last_layer_op as now, so that it remains on top when
2678 doing future relayers (until something else takes over)
2680 timestamp_layer_op (region);
2684 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2686 /* does nothing useful if layering mode is later=higher */
2687 switch (_session.config.get_layer_model()) {
2694 if (region->layer() == 0) {
2695 /* already on the bottom */
2699 move_region_to_layer (0, region, -1);
2700 /* force region's last layer op to zero so that it stays at the bottom
2701 when doing future relayers
2703 region->set_last_layer_op (0);
2707 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2709 RegionList::iterator i;
2710 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2711 list<LayerInfo> layerinfo;
2714 RegionLock rlock (const_cast<Playlist *> (this));
2716 for (i = regions.begin(); i != regions.end(); ++i) {
2726 /* region is moving up, move all regions on intermediate layers
2730 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2731 dest = (*i)->layer() - 1;
2738 /* region is moving down, move all regions on intermediate layers
2742 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2743 dest = (*i)->layer() + 1;
2753 newpair.second = dest;
2755 layerinfo.push_back (newpair);
2761 /* now reset the layers without holding the region lock */
2763 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2764 x->first->set_layer (x->second);
2767 region->set_layer (target_layer);
2769 /* now check all dependents, since we changed the layering */
2771 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2772 check_dependents (x->first, false);
2775 check_dependents (region, false);
2776 notify_layering_changed ();
2784 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2786 RegionList::iterator i;
2792 RegionLock rlock (const_cast<Playlist *> (this));
2794 for (i = regions.begin(); i != regions.end(); ++i) {
2796 if ((*i)->position() >= start) {
2802 if ((*i)->last_frame() > max_framepos - distance) {
2803 new_pos = max_framepos - (*i)->length();
2805 new_pos = (*i)->position() + distance;
2810 if ((*i)->position() > distance) {
2811 new_pos = (*i)->position() - distance;
2817 (*i)->set_position (new_pos, this);
2825 notify_length_changed ();
2831 Playlist::uses_source (boost::shared_ptr<const Source> src) const
2833 RegionLock rlock (const_cast<Playlist*> (this));
2835 for (set<boost::shared_ptr<Region> >::iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
2836 if ((*r)->uses_source (src)) {
2844 boost::shared_ptr<Region>
2845 Playlist::find_region (const ID& id) const
2847 RegionLock rlock (const_cast<Playlist*> (this));
2849 /* searches all regions currently in use by the playlist */
2851 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2852 if ((*i)->id() == id) {
2857 return boost::shared_ptr<Region> ();
2861 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2863 RegionLock rlock (const_cast<Playlist*> (this));
2866 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2875 boost::shared_ptr<Region>
2876 Playlist::region_by_id (const ID& id) const
2878 /* searches all regions ever added to this playlist */
2880 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2881 if ((*i)->id() == id) {
2885 return boost::shared_ptr<Region> ();
2889 Playlist::dump () const
2891 boost::shared_ptr<Region> r;
2893 cerr << "Playlist \"" << _name << "\" " << endl
2894 << regions.size() << " regions "
2897 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2899 cerr << " " << r->name() << " ["
2900 << r->start() << "+" << r->length()
2910 Playlist::set_frozen (bool yn)
2916 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2918 region->set_last_layer_op (++layer_op_counter);
2923 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2927 if (region->locked()) {
2934 RegionLock rlock (const_cast<Playlist*> (this));
2939 RegionList::iterator next;
2941 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2942 if ((*i) == region) {
2946 if (next != regions.end()) {
2948 if ((*next)->locked()) {
2954 if ((*next)->position() != region->last_frame() + 1) {
2955 /* they didn't used to touch, so after shuffle,
2956 just have them swap positions.
2958 new_pos = (*next)->position();
2960 /* they used to touch, so after shuffle,
2961 make sure they still do. put the earlier
2962 region where the later one will end after
2965 new_pos = region->position() + (*next)->length();
2968 (*next)->set_position (region->position(), this);
2969 region->set_position (new_pos, this);
2971 /* avoid a full sort */
2973 regions.erase (i); // removes the region from the list */
2975 regions.insert (next, region); // adds it back after next
2984 RegionList::iterator prev = regions.end();
2986 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2987 if ((*i) == region) {
2989 if (prev != regions.end()) {
2991 if ((*prev)->locked()) {
2996 if (region->position() != (*prev)->last_frame() + 1) {
2997 /* they didn't used to touch, so after shuffle,
2998 just have them swap positions.
3000 new_pos = region->position();
3002 /* they used to touch, so after shuffle,
3003 make sure they still do. put the earlier
3004 one where the later one will end after
3006 new_pos = (*prev)->position() + region->length();
3009 region->set_position ((*prev)->position(), this);
3010 (*prev)->set_position (new_pos, this);
3012 /* avoid a full sort */
3014 regions.erase (i); // remove region
3015 regions.insert (prev, region); // insert region before prev
3031 check_dependents (region, false);
3033 notify_contents_changed();
3039 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
3041 RegionLock rlock (const_cast<Playlist*> (this));
3043 if (regions.size() > 1) {
3051 Playlist::update_after_tempo_map_change ()
3053 RegionLock rlock (const_cast<Playlist*> (this));
3054 RegionList copy (regions.rlist());
3058 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
3059 (*i)->update_position_after_tempo_map_change ();
3066 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
3068 RegionLock rl (this, false);
3069 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3075 Playlist::set_explicit_relayering (bool e)
3077 if (e == false && _explicit_relayering == true) {
3079 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
3080 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
3081 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
3082 at this point would keep regions on the same layers.
3084 From then on in, it's just you and your towel.
3087 RegionLock rl (this);
3088 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3089 (*i)->set_last_layer_op ((*i)->layer ());
3093 _explicit_relayering = e;
3098 Playlist::has_region_at (framepos_t const p) const
3100 RegionLock (const_cast<Playlist *> (this));
3102 RegionList::const_iterator i = regions.begin ();
3103 while (i != regions.end() && !(*i)->covers (p)) {
3107 return (i != regions.end());
3110 /** Remove any region that uses a given source */
3112 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
3114 RegionLock rl (this);
3116 RegionList::iterator i = regions.begin();
3117 while (i != regions.end()) {
3118 RegionList::iterator j = i;
3121 if ((*i)->uses_source (s)) {
3122 remove_region_internal (*i);
3129 /** Look from a session frame time and find the start time of the next region
3130 * which is on the top layer of this playlist.
3131 * @param t Time to look from.
3132 * @return Position of next top-layered region, or max_framepos if there isn't one.
3135 Playlist::find_next_top_layer_position (framepos_t t) const
3137 RegionLock rlock (const_cast<Playlist *> (this));
3139 layer_t const top = top_layer ();
3141 RegionList copy = regions.rlist ();
3142 copy.sort (RegionSortByPosition ());
3144 for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3145 if ((*i)->position() >= t && (*i)->layer() == top) {
3146 return (*i)->position();
3150 return max_framepos;
3154 Playlist::join (const RegionList& r, const std::string& name)
3157 uint32_t channels = 0;
3159 framepos_t earliest_position = max_framepos;
3160 vector<TwoRegions> old_and_new_regions;
3162 boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, name, true);
3164 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3165 earliest_position = min (earliest_position, (*i)->position());
3168 /* enable this so that we do not try to create xfades etc. as we add
3172 pl->in_partition = true;
3174 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3176 /* copy the region */
3178 boost::shared_ptr<Region> original_region = (*i);
3179 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
3181 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
3183 /* make position relative to zero */
3185 pl->add_region (copied_region, original_region->position() - earliest_position);
3187 /* use the maximum number of channels for any region */
3189 channels = max (channels, original_region->n_channels());
3191 /* it will go above the layer of the highest existing region */
3193 layer = max (layer, original_region->layer());
3196 pl->in_partition = false;
3198 /* now create a new PlaylistSource for each channel in the new playlist */
3201 pair<framepos_t,framepos_t> extent = pl->get_extent();
3203 for (uint32_t chn = 0; chn < channels; ++chn) {
3204 sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, name, chn, 0, extent.second, false, false));
3207 /* now a new region using the list of sources */
3209 plist.add (Properties::start, 0);
3210 plist.add (Properties::length, extent.second);
3211 plist.add (Properties::name, name);
3212 plist.add (Properties::layer, layer+1);
3214 boost::shared_ptr<Region> compound_region = RegionFactory::create (sources, plist, true);
3216 /* add any dependent regions to the new playlist */
3218 copy_dependents (old_and_new_regions, pl);
3220 /* remove all the selected regions from the current playlist
3225 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3229 /* add the new region at the right location */
3231 add_region (compound_region, earliest_position);
3239 Playlist::max_source_level () const
3241 RegionLock rlock (const_cast<Playlist *> (this));
3244 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3245 lvl = max (lvl, (*i)->max_source_level());
3253 Playlist::count_joined_regions () const
3255 RegionLock rlock (const_cast<Playlist *> (this));
3258 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3259 if ((*i)->max_source_level() > 0) {