2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <boost/lexical_cast.hpp>
31 #include "pbd/failed_constructor.h"
32 #include "pbd/stateful_diff_command.h"
33 #include "pbd/xml++.h"
34 #include "pbd/stacktrace.h"
36 #include "ardour/debug.h"
37 #include "ardour/playlist.h"
38 #include "ardour/session.h"
39 #include "ardour/region.h"
40 #include "ardour/region_factory.h"
41 #include "ardour/playlist_factory.h"
42 #include "ardour/transient_detector.h"
43 #include "ardour/session_playlists.h"
48 using namespace ARDOUR;
52 namespace Properties {
53 PBD::PropertyDescriptor<bool> regions;
57 struct ShowMeTheList {
58 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
60 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
62 boost::shared_ptr<Playlist> playlist;
66 struct RegionSortByLayer {
67 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
68 return a->layer() < b->layer();
72 struct RegionSortByLayerWithPending {
73 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
75 double p = a->layer ();
76 if (a->pending_explicit_relayer()) {
80 double q = b->layer ();
81 if (b->pending_explicit_relayer()) {
89 struct RegionSortByPosition {
90 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
91 return a->position() < b->position();
95 struct RegionSortByLastLayerOp {
96 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
97 return a->last_layer_op() < b->last_layer_op();
102 Playlist::make_property_quarks ()
104 Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
105 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n", Properties::regions.property_id));
108 RegionListProperty::RegionListProperty (Playlist& pl)
109 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
115 RegionListProperty::RegionListProperty (RegionListProperty const & p)
116 : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
117 , _playlist (p._playlist)
123 RegionListProperty::clone () const
125 return new RegionListProperty (*this);
129 RegionListProperty::create () const
131 return new RegionListProperty (_playlist);
135 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
137 /* All regions (even those which are deleted) have their state saved by other
138 code, so we can just store ID here.
141 node.add_property ("id", region->id().to_s ());
144 boost::shared_ptr<Region>
145 RegionListProperty::get_content_from_xml (XMLNode const & node) const
147 XMLProperty const * prop = node.property ("id");
150 PBD::ID id (prop->value ());
152 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
155 ret = RegionFactory::region_by_id (id);
161 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
162 : SessionObject(sess, nom)
167 first_set_state = false;
173 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
174 : SessionObject(sess, "unnamed playlist")
180 const XMLProperty* prop = node.property("type");
181 assert(!prop || DataType(prop->value()) == _type);
185 _name = "unnamed"; /* reset by set_state */
188 /* set state called by derived class */
191 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
192 : SessionObject(other->_session, namestr)
194 , _type(other->_type)
195 , _orig_diskstream_id (other->_orig_diskstream_id)
200 other->copy_regions (tmp);
204 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
205 add_region_internal( (*x), (*x)->position());
210 _splicing = other->_splicing;
211 _nudging = other->_nudging;
212 _edit_mode = other->_edit_mode;
215 first_set_state = false;
217 in_partition = false;
219 _read_data_count = 0;
220 _frozen = other->_frozen;
222 layer_op_counter = other->layer_op_counter;
223 freeze_length = other->freeze_length;
226 Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
227 : SessionObject(other->_session, str)
229 , _type(other->_type)
230 , _orig_diskstream_id (other->_orig_diskstream_id)
232 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
234 framepos_t end = start + cnt - 1;
240 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
242 boost::shared_ptr<Region> region;
243 boost::shared_ptr<Region> new_region;
244 frameoffset_t offset = 0;
245 framepos_t position = 0;
252 overlap = region->coverage (start, end);
258 case OverlapInternal:
259 offset = start - region->position();
266 position = region->position() - start;
267 len = end - region->position();
271 offset = start - region->position();
273 len = region->length() - offset;
276 case OverlapExternal:
278 position = region->position() - start;
279 len = region->length();
283 RegionFactory::region_name (new_name, region->name(), false);
287 plist.add (Properties::start, region->start() + offset);
288 plist.add (Properties::length, len);
289 plist.add (Properties::name, new_name);
290 plist.add (Properties::layer, region->layer());
292 new_region = RegionFactory::RegionFactory::create (region, plist);
294 add_region_internal (new_region, position);
298 first_set_state = false;
300 /* this constructor does NOT notify others (session) */
307 InUse (true); /* EMIT SIGNAL */
318 InUse (false); /* EMIT SIGNAL */
323 Playlist::copy_regions (RegionList& newlist) const
325 RegionLock rlock (const_cast<Playlist *> (this));
327 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
328 newlist.push_back (RegionFactory::RegionFactory::create (*i, true));
333 Playlist::init (bool hide)
335 add_property (regions);
336 _xml_node_name = X_("Playlist");
338 g_atomic_int_set (&block_notifications, 0);
339 g_atomic_int_set (&ignore_state_changes, 0);
340 pending_contents_change = false;
341 pending_length = false;
342 pending_layering = false;
343 first_set_state = true;
351 _edit_mode = Config->get_edit_mode();
353 in_partition = false;
355 _read_data_count = 0;
357 layer_op_counter = 0;
359 _explicit_relayering = false;
361 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
362 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
364 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
367 Playlist::~Playlist ()
369 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
372 RegionLock rl (this);
374 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
375 (*i)->set_playlist (boost::shared_ptr<Playlist>());
379 /* GoingAway must be emitted by derived classes */
383 Playlist::_set_sort_id ()
386 Playlists are given names like <track name>.<id>
387 or <track name>.<edit group name>.<id> where id
388 is an integer. We extract the id and sort by that.
391 size_t dot_position = _name.val().find_last_of(".");
393 if (dot_position == string::npos) {
396 string t = _name.val().substr(dot_position + 1);
399 _sort_id = boost::lexical_cast<int>(t);
402 catch (boost::bad_lexical_cast e) {
409 Playlist::set_name (const string& str)
411 /* in a typical situation, a playlist is being used
412 by one diskstream and also is referenced by the
413 Session. if there are more references than that,
414 then don't change the name.
421 bool ret = SessionObject::set_name(str);
428 /***********************************************************************
429 CHANGE NOTIFICATION HANDLING
431 Notifications must be delayed till the region_lock is released. This
432 is necessary because handlers for the signals may need to acquire
433 the lock (e.g. to read from the playlist).
434 ***********************************************************************/
437 Playlist::begin_undo ()
444 Playlist::end_undo ()
453 delay_notifications ();
454 g_atomic_int_inc (&ignore_state_changes);
457 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
459 Playlist::thaw (bool from_undo)
461 g_atomic_int_dec_and_test (&ignore_state_changes);
462 release_notifications (from_undo);
467 Playlist::delay_notifications ()
469 g_atomic_int_inc (&block_notifications);
470 freeze_length = _get_extent().second;
473 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
475 Playlist::release_notifications (bool from_undo)
477 if (g_atomic_int_dec_and_test (&block_notifications)) {
478 flush_notifications (from_undo);
484 Playlist::notify_contents_changed ()
486 if (holding_state ()) {
487 pending_contents_change = true;
489 pending_contents_change = false;
490 ContentsChanged(); /* EMIT SIGNAL */
495 Playlist::notify_layering_changed ()
497 if (holding_state ()) {
498 pending_layering = true;
500 pending_layering = false;
501 LayeringChanged(); /* EMIT SIGNAL */
506 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
508 if (holding_state ()) {
509 pending_removes.insert (r);
510 pending_contents_change = true;
511 pending_length = true;
513 /* this might not be true, but we have to act
514 as though it could be.
516 pending_length = false;
517 LengthChanged (); /* EMIT SIGNAL */
518 pending_contents_change = false;
519 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
520 ContentsChanged (); /* EMIT SIGNAL */
525 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
527 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
529 if (holding_state ()) {
531 pending_range_moves.push_back (move);
535 list< Evoral::RangeMove<framepos_t> > m;
537 RangesMoved (m, false);
543 Playlist::notify_region_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 cerr << "Playlist: region added at " << position << endl;
832 possibly_splice_unlocked (position, region->length(), region);
834 cerr << "Playlist: post-splice, region @ " << region->position() << endl;
836 if (!holding_state ()) {
837 /* layers get assigned from XML state, and are not reset during undo/redo */
841 /* we need to notify the existence of new region before checking dependents. Ick. */
843 notify_region_added (region);
845 if (!holding_state ()) {
847 check_dependents (region, false);
849 if (old_length != _get_extent().second) {
850 notify_length_changed ();
854 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
860 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
862 RegionLock rlock (this);
864 bool old_sp = _splicing;
867 remove_region_internal (old);
868 add_region_internal (newr, pos);
872 possibly_splice_unlocked (pos, old->length() - newr->length());
876 Playlist::remove_region (boost::shared_ptr<Region> region)
878 RegionLock rlock (this);
879 remove_region_internal (region);
883 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
885 RegionList::iterator i;
886 framecnt_t old_length = 0;
889 if (!holding_state()) {
890 old_length = _get_extent().second;
895 region->set_playlist (boost::weak_ptr<Playlist>());
898 /* XXX should probably freeze here .... */
900 for (i = regions.begin(); i != regions.end(); ++i) {
903 framepos_t pos = (*i)->position();
904 framecnt_t distance = (*i)->length();
908 possibly_splice_unlocked (pos, -distance);
910 if (!holding_state ()) {
912 remove_dependents (region);
914 if (old_length != _get_extent().second) {
915 notify_length_changed ();
919 notify_region_removed (region);
929 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
931 if (Config->get_use_overlap_equivalency()) {
932 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
933 if ((*i)->overlap_equivalent (other)) {
934 results.push_back ((*i));
938 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
939 if ((*i)->equivalent (other)) {
940 results.push_back ((*i));
947 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
949 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
951 if ((*i) && (*i)->region_list_equivalent (other)) {
952 results.push_back (*i);
958 Playlist::partition (framepos_t start, framepos_t end, bool cut)
962 partition_internal (start, end, cut, thawlist);
964 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
965 (*i)->resume_property_changes ();
970 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
972 RegionList new_regions;
975 RegionLock rlock (this);
977 boost::shared_ptr<Region> region;
978 boost::shared_ptr<Region> current;
980 RegionList::iterator tmp;
982 framepos_t pos1, pos2, pos3, pos4;
986 /* need to work from a copy, because otherwise the regions we add during the process
987 get operated on as well.
990 RegionList copy = regions.rlist();
992 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
999 if (current->first_frame() >= start && current->last_frame() < end) {
1002 remove_region_internal (current);
1008 /* coverage will return OverlapStart if the start coincides
1009 with the end point. we do not partition such a region,
1010 so catch this special case.
1013 if (current->first_frame() >= end) {
1017 if ((overlap = current->coverage (start, end)) == OverlapNone) {
1021 pos1 = current->position();
1024 pos4 = current->last_frame();
1026 if (overlap == OverlapInternal) {
1027 /* split: we need 3 new regions, the front, middle and end.
1028 cut: we need 2 regions, the front and end.
1033 ---------------*************************------------
1036 ---------------*****++++++++++++++++====------------
1038 ---------------*****----------------====------------
1043 /* "middle" ++++++ */
1045 RegionFactory::region_name (new_name, current->name(), false);
1049 plist.add (Properties::start, current->start() + (pos2 - pos1));
1050 plist.add (Properties::length, pos3 - pos2);
1051 plist.add (Properties::name, new_name);
1052 plist.add (Properties::layer, regions.size());
1053 plist.add (Properties::automatic, true);
1054 plist.add (Properties::left_of_split, true);
1055 plist.add (Properties::right_of_split, true);
1057 region = RegionFactory::create (current, plist);
1058 add_region_internal (region, start);
1059 new_regions.push_back (region);
1064 RegionFactory::region_name (new_name, current->name(), false);
1068 plist.add (Properties::start, current->start() + (pos3 - pos1));
1069 plist.add (Properties::length, pos4 - pos3);
1070 plist.add (Properties::name, new_name);
1071 plist.add (Properties::layer, regions.size());
1072 plist.add (Properties::automatic, true);
1073 plist.add (Properties::right_of_split, true);
1075 region = RegionFactory::create (current, plist);
1077 add_region_internal (region, end);
1078 new_regions.push_back (region);
1082 current->suspend_property_changes ();
1083 thawlist.push_back (current);
1084 current->cut_end (pos2 - 1, this);
1086 } else if (overlap == OverlapEnd) {
1090 ---------------*************************------------
1093 ---------------**************+++++++++++------------
1095 ---------------**************-----------------------
1102 RegionFactory::region_name (new_name, current->name(), false);
1106 plist.add (Properties::start, current->start() + (pos2 - pos1));
1107 plist.add (Properties::length, pos4 - pos2);
1108 plist.add (Properties::name, new_name);
1109 plist.add (Properties::layer, regions.size());
1110 plist.add (Properties::automatic, true);
1111 plist.add (Properties::left_of_split, true);
1113 region = RegionFactory::create (current, plist);
1115 add_region_internal (region, start);
1116 new_regions.push_back (region);
1121 current->suspend_property_changes ();
1122 thawlist.push_back (current);
1123 current->cut_end (pos2 - 1, this);
1125 } else if (overlap == OverlapStart) {
1127 /* split: we need 2 regions: the front and the end.
1128 cut: just trim current to skip the cut area
1133 ---------------*************************------------
1137 ---------------****+++++++++++++++++++++------------
1139 -------------------*********************------------
1145 RegionFactory::region_name (new_name, current->name(), false);
1149 plist.add (Properties::start, current->start());
1150 plist.add (Properties::length, pos3 - pos1);
1151 plist.add (Properties::name, new_name);
1152 plist.add (Properties::layer, regions.size());
1153 plist.add (Properties::automatic, true);
1154 plist.add (Properties::right_of_split, true);
1156 region = RegionFactory::create (current, plist);
1158 add_region_internal (region, pos1);
1159 new_regions.push_back (region);
1164 current->suspend_property_changes ();
1165 thawlist.push_back (current);
1166 current->trim_front (pos3, this);
1167 } else if (overlap == OverlapExternal) {
1169 /* split: no split required.
1170 cut: remove the region.
1175 ---------------*************************------------
1179 ---------------*************************------------
1181 ----------------------------------------------------
1186 remove_region_internal (current);
1189 new_regions.push_back (current);
1193 in_partition = false;
1196 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1197 check_dependents (*i, false);
1201 boost::shared_ptr<Playlist>
1202 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1204 boost::shared_ptr<Playlist> ret;
1205 boost::shared_ptr<Playlist> pl;
1208 if (ranges.empty()) {
1209 return boost::shared_ptr<Playlist>();
1212 start = ranges.front().start;
1214 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1216 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1218 if (i == ranges.begin()) {
1222 /* paste the next section into the nascent playlist,
1223 offset to reflect the start of the first range we
1227 ret->paste (pl, (*i).start - start, 1.0f);
1234 boost::shared_ptr<Playlist>
1235 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1237 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1238 return cut_copy (pmf, ranges, result_is_hidden);
1241 boost::shared_ptr<Playlist>
1242 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1244 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1245 return cut_copy (pmf, ranges, result_is_hidden);
1248 boost::shared_ptr<Playlist>
1249 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1251 boost::shared_ptr<Playlist> the_copy;
1252 RegionList thawlist;
1255 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1256 string new_name = _name;
1260 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1261 return boost::shared_ptr<Playlist>();
1264 partition_internal (start, start+cnt-1, true, thawlist);
1266 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1267 (*i)->resume_property_changes();
1273 boost::shared_ptr<Playlist>
1274 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1278 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1279 string new_name = _name;
1283 cnt = min (_get_extent().second - start, cnt);
1284 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1288 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1290 times = fabs (times);
1293 RegionLock rl1 (this);
1294 RegionLock rl2 (other.get());
1296 framecnt_t const old_length = _get_extent().second;
1298 int itimes = (int) floor (times);
1299 framepos_t pos = position;
1300 framecnt_t const shift = other->_get_extent().second;
1301 layer_t top_layer = regions.size();
1304 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1305 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1307 /* put these new regions on top of all existing ones, but preserve
1308 the ordering they had in the original playlist.
1311 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1312 cerr << "DEBUG: add new region at " << pos << endl;
1313 add_region_internal (copy_of_region, (*i)->position() + pos);
1319 /* XXX shall we handle fractional cases at some point? */
1321 if (old_length != _get_extent().second) {
1322 notify_length_changed ();
1333 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1335 times = fabs (times);
1337 RegionLock rl (this);
1338 int itimes = (int) floor (times);
1339 framepos_t pos = position + 1;
1342 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1343 add_region_internal (copy, pos);
1344 pos += region->length();
1347 if (floor (times) != times) {
1348 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1350 RegionFactory::region_name (name, region->name(), false);
1355 plist.add (Properties::start, region->start());
1356 plist.add (Properties::length, length);
1357 plist.add (Properties::name, name);
1359 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1360 add_region_internal (sub, pos);
1366 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1368 RegionLock rlock (this);
1369 RegionList copy (regions.rlist());
1372 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1374 if ((*r)->last_frame() < at) {
1379 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1380 /* intersected region */
1381 if (!move_intersected) {
1386 /* do not move regions glued to music time - that
1387 has to be done separately.
1390 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1391 fixup.push_back (*r);
1395 (*r)->set_position ((*r)->position() + distance, this);
1398 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1399 (*r)->recompute_position_from_lock_style ();
1404 Playlist::split (framepos_t at)
1406 RegionLock rlock (this);
1407 RegionList copy (regions.rlist());
1409 /* use a copy since this operation can modify the region list
1412 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1413 _split_region (*r, at);
1418 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1420 RegionLock rl (this);
1421 _split_region (region, playlist_position);
1425 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1427 if (!region->covers (playlist_position)) {
1431 if (region->position() == playlist_position ||
1432 region->last_frame() == playlist_position) {
1436 boost::shared_ptr<Region> left;
1437 boost::shared_ptr<Region> right;
1438 frameoffset_t before;
1439 frameoffset_t after;
1443 /* split doesn't change anything about length, so don't try to splice */
1445 bool old_sp = _splicing;
1448 before = playlist_position - region->position();
1449 after = region->length() - before;
1451 RegionFactory::region_name (before_name, region->name(), false);
1456 plist.add (Properties::position, region->position ());
1457 plist.add (Properties::length, before);
1458 plist.add (Properties::name, before_name);
1459 plist.add (Properties::left_of_split, true);
1461 /* note: we must use the version of ::create with an offset here,
1462 since it supplies that offset to the Region constructor, which
1463 is necessary to get audio region gain envelopes right.
1465 left = RegionFactory::create (region, 0, plist);
1468 RegionFactory::region_name (after_name, region->name(), false);
1473 plist.add (Properties::position, region->position() + before);
1474 plist.add (Properties::length, after);
1475 plist.add (Properties::name, after_name);
1476 plist.add (Properties::right_of_split, true);
1478 /* same note as above */
1479 right = RegionFactory::create (region, before, plist);
1482 add_region_internal (left, region->position());
1483 add_region_internal (right, region->position() + before);
1485 uint64_t orig_layer_op = region->last_layer_op();
1486 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1487 if ((*i)->last_layer_op() > orig_layer_op) {
1488 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1492 left->set_last_layer_op ( orig_layer_op );
1493 right->set_last_layer_op ( orig_layer_op + 1);
1497 finalize_split_region (region, left, right);
1499 remove_region_internal (region);
1505 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1507 if (_splicing || in_set_state) {
1508 /* don't respond to splicing moves or state setting */
1512 if (_edit_mode == Splice) {
1513 splice_locked (at, distance, exclude);
1518 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1520 if (_splicing || in_set_state) {
1521 /* don't respond to splicing moves or state setting */
1525 if (_edit_mode == Splice) {
1526 splice_unlocked (at, distance, exclude);
1531 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1534 RegionLock rl (this);
1535 core_splice (at, distance, exclude);
1540 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1542 core_splice (at, distance, exclude);
1546 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1550 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1552 if (exclude && (*i) == exclude) {
1556 if ((*i)->position() >= at) {
1557 framepos_t new_pos = (*i)->position() + distance;
1560 } else if (new_pos >= max_framepos - (*i)->length()) {
1561 new_pos = max_framepos - (*i)->length();
1564 (*i)->set_position (new_pos, this);
1570 notify_length_changed ();
1574 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1576 if (in_set_state || _splicing || _nudging || _shuffling) {
1580 if (what_changed.contains (Properties::position)) {
1582 /* remove it from the list then add it back in
1583 the right place again.
1586 RegionSortByPosition cmp;
1588 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1590 if (i == regions.end()) {
1591 /* the region bounds are being modified but its not currently
1592 in the region list. we will use its bounds correctly when/if
1599 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1602 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1604 frameoffset_t delta = 0;
1606 if (what_changed.contains (Properties::position)) {
1607 delta = region->position() - region->last_position();
1610 if (what_changed.contains (Properties::length)) {
1611 delta += region->length() - region->last_length();
1615 possibly_splice (region->last_position() + region->last_length(), delta, region);
1618 if (holding_state ()) {
1619 pending_bounds.push_back (region);
1621 if (_session.config.get_layer_model() == MoveAddHigher) {
1622 /* it moved or changed length, so change the timestamp */
1623 timestamp_layer_op (region);
1626 notify_length_changed ();
1628 check_dependents (region, false);
1634 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1636 boost::shared_ptr<Region> region (weak_region.lock());
1642 /* this makes a virtual call to the right kind of playlist ... */
1644 region_changed (what_changed, region);
1648 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1650 PropertyChange our_interests;
1651 PropertyChange bounds;
1652 PropertyChange pos_and_length;
1655 if (in_set_state || in_flush) {
1659 our_interests.add (Properties::muted);
1660 our_interests.add (Properties::layer);
1661 our_interests.add (Properties::opaque);
1663 bounds.add (Properties::start);
1664 bounds.add (Properties::position);
1665 bounds.add (Properties::length);
1667 pos_and_length.add (Properties::position);
1668 pos_and_length.add (Properties::length);
1670 if (what_changed.contains (bounds)) {
1671 region_bounds_changed (what_changed, region);
1672 save = !(_splicing || _nudging);
1675 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1676 check_dependents (region, false);
1679 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1680 notify_region_moved (region);
1681 } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1682 notify_region_end_trimmed (region);
1683 } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1684 notify_region_start_trimmed (region);
1687 /* don't notify about layer changes, since we are the only object that can initiate
1688 them, and we notify in ::relayer()
1691 if (what_changed.contains (our_interests)) {
1699 Playlist::drop_regions ()
1701 RegionLock rl (this);
1703 all_regions.clear ();
1707 Playlist::clear (bool with_signals)
1710 RegionLock rl (this);
1712 region_state_changed_connections.drop_connections ();
1714 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1715 pending_removes.insert (*i);
1720 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1721 remove_dependents (*s);
1727 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1728 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1731 pending_removes.clear ();
1732 pending_length = false;
1734 pending_contents_change = false;
1740 /***********************************************************************
1742 **********************************************************************/
1744 Playlist::RegionList *
1745 Playlist::regions_at (framepos_t frame)
1748 RegionLock rlock (this);
1749 return find_regions_at (frame);
1753 Playlist::count_regions_at (framepos_t frame)
1755 RegionLock rlock (this);
1758 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1759 if ((*i)->covers (frame)) {
1767 boost::shared_ptr<Region>
1768 Playlist::top_region_at (framepos_t frame)
1771 RegionLock rlock (this);
1772 RegionList *rlist = find_regions_at (frame);
1773 boost::shared_ptr<Region> region;
1775 if (rlist->size()) {
1776 RegionSortByLayer cmp;
1778 region = rlist->back();
1785 boost::shared_ptr<Region>
1786 Playlist::top_unmuted_region_at (framepos_t frame)
1789 RegionLock rlock (this);
1790 RegionList *rlist = find_regions_at (frame);
1792 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1794 RegionList::iterator tmp = i;
1797 if ((*i)->muted()) {
1804 boost::shared_ptr<Region> region;
1806 if (rlist->size()) {
1807 RegionSortByLayer cmp;
1809 region = rlist->back();
1816 Playlist::RegionList*
1817 Playlist::regions_to_read (framepos_t start, framepos_t end)
1819 /* Caller must hold lock */
1821 RegionList covering;
1822 set<framepos_t> to_check;
1823 set<boost::shared_ptr<Region> > unique;
1825 to_check.insert (start);
1826 to_check.insert (end);
1828 DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1830 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1832 /* find all/any regions that span start+end */
1834 switch ((*i)->coverage (start, end)) {
1838 case OverlapInternal:
1839 covering.push_back (*i);
1840 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1844 to_check.insert ((*i)->position());
1845 if ((*i)->position() != 0) {
1846 to_check.insert ((*i)->position()-1);
1848 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1849 covering.push_back (*i);
1853 to_check.insert ((*i)->last_frame());
1854 to_check.insert ((*i)->last_frame()+1);
1855 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1856 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1857 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1858 covering.push_back (*i);
1861 case OverlapExternal:
1862 covering.push_back (*i);
1863 to_check.insert ((*i)->position());
1864 if ((*i)->position() != 0) {
1865 to_check.insert ((*i)->position()-1);
1867 to_check.insert ((*i)->last_frame());
1868 to_check.insert ((*i)->last_frame()+1);
1869 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1870 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1871 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1875 /* don't go too far */
1877 if ((*i)->position() > end) {
1882 RegionList* rlist = new RegionList;
1884 /* find all the regions that cover each position .... */
1886 if (covering.size() == 1) {
1888 rlist->push_back (covering.front());
1889 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1894 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1898 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1900 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1902 if ((*x)->covers (*t)) {
1903 here.push_back (*x);
1904 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1908 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1915 RegionSortByLayer cmp;
1918 /* ... and get the top/transparent regions at "here" */
1920 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1924 if ((*c)->opaque()) {
1926 /* the other regions at this position are hidden by this one */
1927 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1934 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1935 rlist->push_back (*s);
1938 if (rlist->size() > 1) {
1939 /* now sort by time order */
1941 RegionSortByPosition cmp;
1946 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1951 Playlist::RegionList *
1952 Playlist::find_regions_at (framepos_t frame)
1954 /* Caller must hold lock */
1956 RegionList *rlist = new RegionList;
1958 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1959 if ((*i)->covers (frame)) {
1960 rlist->push_back (*i);
1967 Playlist::RegionList *
1968 Playlist::regions_touched (framepos_t start, framepos_t end)
1970 RegionLock rlock (this);
1971 RegionList *rlist = new RegionList;
1973 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1974 if ((*i)->coverage (start, end) != OverlapNone) {
1975 rlist->push_back (*i);
1983 Playlist::find_next_transient (framepos_t from, int dir)
1985 RegionLock rlock (this);
1986 AnalysisFeatureList points;
1987 AnalysisFeatureList these_points;
1989 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1991 if ((*i)->last_frame() < from) {
1995 if ((*i)->first_frame() > from) {
2000 (*i)->get_transients (these_points);
2002 /* add first frame, just, err, because */
2004 these_points.push_back ((*i)->first_frame());
2006 points.insert (points.end(), these_points.begin(), these_points.end());
2007 these_points.clear ();
2010 if (points.empty()) {
2014 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
2015 bool reached = false;
2018 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
2023 if (reached && (*x) > from) {
2028 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2033 if (reached && (*x) < from) {
2042 boost::shared_ptr<Region>
2043 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
2045 RegionLock rlock (this);
2046 boost::shared_ptr<Region> ret;
2047 framepos_t closest = max_framepos;
2049 bool end_iter = false;
2051 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2055 frameoffset_t distance;
2056 boost::shared_ptr<Region> r = (*i);
2061 pos = r->first_frame ();
2064 pos = r->last_frame ();
2067 pos = r->sync_position ();
2072 case 1: /* forwards */
2075 if ((distance = pos - frame) < closest) {
2084 default: /* backwards */
2087 if ((distance = frame - pos) < closest) {
2104 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2106 RegionLock rlock (this);
2108 framepos_t closest = max_framepos;
2109 framepos_t ret = -1;
2113 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2115 boost::shared_ptr<Region> r = (*i);
2116 frameoffset_t distance;
2118 if (r->first_frame() > frame) {
2120 distance = r->first_frame() - frame;
2122 if (distance < closest) {
2123 ret = r->first_frame();
2128 if (r->last_frame () > frame) {
2130 distance = r->last_frame () - frame;
2132 if (distance < closest) {
2133 ret = r->last_frame ();
2141 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2143 boost::shared_ptr<Region> r = (*i);
2144 frameoffset_t distance;
2146 if (r->last_frame() < frame) {
2148 distance = frame - r->last_frame();
2150 if (distance < closest) {
2151 ret = r->last_frame();
2156 if (r->first_frame() < frame) {
2158 distance = frame - r->first_frame();
2160 if (distance < closest) {
2161 ret = r->first_frame();
2172 /***********************************************************************/
2178 Playlist::mark_session_dirty ()
2180 if (!in_set_state && !holding_state ()) {
2181 _session.set_dirty();
2186 Playlist::rdiff (vector<Command*>& cmds) const
2188 RegionLock rlock (const_cast<Playlist *> (this));
2189 Stateful::rdiff (cmds);
2193 Playlist::clear_owned_changes ()
2195 RegionLock rlock (this);
2196 Stateful::clear_owned_changes ();
2200 Playlist::update (const RegionListProperty::ChangeRecord& change)
2202 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2203 name(), change.added.size(), change.removed.size()));
2206 /* add the added regions */
2207 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2208 add_region ((*i), (*i)->position());
2210 /* remove the removed regions */
2211 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2219 Playlist::set_state (const XMLNode& node, int version)
2223 XMLNodeConstIterator niter;
2224 XMLPropertyList plist;
2225 XMLPropertyConstIterator piter;
2227 boost::shared_ptr<Region> region;
2232 if (node.name() != "Playlist") {
2239 plist = node.properties();
2241 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2245 if (prop->name() == X_("name")) {
2246 _name = prop->value();
2248 } else if (prop->name() == X_("id")) {
2249 _id = prop->value();
2250 } else if (prop->name() == X_("orig_diskstream_id")) {
2251 _orig_diskstream_id = prop->value ();
2252 } else if (prop->name() == X_("frozen")) {
2253 _frozen = string_is_affirmative (prop->value());
2259 nlist = node.children();
2261 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2265 if (child->name() == "Region") {
2267 if ((prop = child->property ("id")) == 0) {
2268 error << _("region state node has no ID, ignored") << endmsg;
2272 ID id = prop->value ();
2274 if ((region = region_by_id (id))) {
2276 region->suspend_property_changes ();
2278 if (region->set_state (*child, version)) {
2279 region->resume_property_changes ();
2283 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2284 region->suspend_property_changes ();
2286 error << _("Playlist: cannot create region from XML") << endmsg;
2291 add_region (region, region->position(), 1.0);
2293 // So that layer_op ordering doesn't get screwed up
2294 region->set_last_layer_op( region->layer());
2295 region->resume_property_changes ();
2299 /* update dependents, which was not done during add_region_internal
2300 due to in_set_state being true
2303 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2304 check_dependents (*r, false);
2308 notify_contents_changed ();
2311 first_set_state = false;
2316 Playlist::get_state()
2318 return state (true);
2322 Playlist::get_template()
2324 return state (false);
2327 /** @param full_state true to include regions in the returned state, otherwise false.
2330 Playlist::state (bool full_state)
2332 XMLNode *node = new XMLNode (X_("Playlist"));
2335 node->add_property (X_("id"), id().to_s());
2336 node->add_property (X_("name"), _name);
2337 node->add_property (X_("type"), _type.to_string());
2339 _orig_diskstream_id.print (buf, sizeof (buf));
2340 node->add_property (X_("orig_diskstream_id"), buf);
2341 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2344 RegionLock rlock (this, false);
2346 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2347 node->add_child_nocopy ((*i)->get_state());
2352 node->add_child_copy (*_extra_xml);
2359 Playlist::empty() const
2361 RegionLock rlock (const_cast<Playlist *>(this), false);
2362 return regions.empty();
2366 Playlist::n_regions() const
2368 RegionLock rlock (const_cast<Playlist *>(this), false);
2369 return regions.size();
2372 pair<framepos_t, framepos_t>
2373 Playlist::get_extent () const
2375 RegionLock rlock (const_cast<Playlist *>(this), false);
2376 return _get_extent ();
2379 pair<framepos_t, framepos_t>
2380 Playlist::_get_extent () const
2382 pair<framepos_t, framepos_t> ext (max_framepos, 0);
2384 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2385 pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2386 if (e.first < ext.first) {
2387 ext.first = e.first;
2389 if (e.second > ext.second) {
2390 ext.second = e.second;
2398 Playlist::bump_name (string name, Session &session)
2400 string newname = name;
2403 newname = bump_name_once (newname, '.');
2404 } while (session.playlists->by_name (newname)!=NULL);
2411 Playlist::top_layer() const
2413 RegionLock rlock (const_cast<Playlist *> (this));
2416 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2417 top = max (top, (*i)->layer());
2423 Playlist::set_edit_mode (EditMode mode)
2428 /********************
2430 ********************/
2433 Playlist::relayer ()
2435 /* never compute layers when changing state for undo/redo or setting from XML */
2437 if (in_update || in_set_state) {
2441 bool changed = false;
2443 /* Build up a new list of regions on each layer, stored in a set of lists
2444 each of which represent some period of time on some layer. The idea
2445 is to avoid having to search the entire region list to establish whether
2446 each region overlaps another */
2448 /* how many pieces to divide this playlist's time up into */
2449 int const divisions = 512;
2451 /* find the start and end positions of the regions on this playlist */
2452 framepos_t start = INT64_MAX;
2454 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2455 start = min (start, (*i)->position());
2456 end = max (end, (*i)->position() + (*i)->length());
2459 /* hence the size of each time division */
2460 double const division_size = (end - start) / double (divisions);
2462 vector<vector<RegionList> > layers;
2463 layers.push_back (vector<RegionList> (divisions));
2465 /* we want to go through regions from desired lowest to desired highest layer,
2466 which depends on the layer model
2469 RegionList copy = regions.rlist();
2471 /* sort according to the model and the layering mode that we're in */
2473 if (_explicit_relayering) {
2475 copy.sort (RegionSortByLayerWithPending ());
2477 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2479 copy.sort (RegionSortByLastLayerOp ());
2484 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2486 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2487 (*i)->set_pending_explicit_relayer (false);
2489 /* find the time divisions that this region covers; if there are no regions on the list,
2490 division_size will equal 0 and in this case we'll just say that
2491 start_division = end_division = 0.
2493 int start_division = 0;
2494 int end_division = 0;
2496 if (division_size > 0) {
2497 start_division = floor ( ((*i)->position() - start) / division_size);
2498 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2499 if (end_division == divisions) {
2504 assert (divisions == 0 || end_division < divisions);
2506 /* find the lowest layer that this region can go on */
2507 size_t j = layers.size();
2509 /* try layer j - 1; it can go on if it overlaps no other region
2510 that is already on that layer
2513 bool overlap = false;
2514 for (int k = start_division; k <= end_division; ++k) {
2515 RegionList::iterator l = layers[j-1][k].begin ();
2516 while (l != layers[j-1][k].end()) {
2517 if ((*l)->overlap_equivalent (*i)) {
2530 /* overlap, so we must use layer j */
2537 if (j == layers.size()) {
2538 /* we need a new layer for this region */
2539 layers.push_back (vector<RegionList> (divisions));
2542 /* put a reference to this region in each of the divisions that it exists in */
2543 for (int k = start_division; k <= end_division; ++k) {
2544 layers[j][k].push_back (*i);
2547 if ((*i)->layer() != j) {
2551 (*i)->set_layer (j);
2555 notify_layering_changed ();
2559 /* XXX these layer functions are all deprecated */
2562 Playlist::raise_region (boost::shared_ptr<Region> region)
2564 uint32_t top = regions.size() - 1;
2565 layer_t target = region->layer() + 1U;
2567 if (target >= top) {
2568 /* its already at the effective top */
2572 move_region_to_layer (target, region, 1);
2576 Playlist::lower_region (boost::shared_ptr<Region> region)
2578 if (region->layer() == 0) {
2579 /* its already at the bottom */
2583 layer_t target = region->layer() - 1U;
2585 move_region_to_layer (target, region, -1);
2589 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2591 /* does nothing useful if layering mode is later=higher */
2592 switch (_session.config.get_layer_model()) {
2599 layer_t top = regions.size() - 1;
2601 if (region->layer() >= top) {
2602 /* already on the top */
2606 move_region_to_layer (top, region, 1);
2607 /* mark the region's last_layer_op as now, so that it remains on top when
2608 doing future relayers (until something else takes over)
2610 timestamp_layer_op (region);
2614 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2616 /* does nothing useful if layering mode is later=higher */
2617 switch (_session.config.get_layer_model()) {
2624 if (region->layer() == 0) {
2625 /* already on the bottom */
2629 move_region_to_layer (0, region, -1);
2630 /* force region's last layer op to zero so that it stays at the bottom
2631 when doing future relayers
2633 region->set_last_layer_op (0);
2637 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2639 RegionList::iterator i;
2640 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2641 list<LayerInfo> layerinfo;
2644 RegionLock rlock (const_cast<Playlist *> (this));
2646 for (i = regions.begin(); i != regions.end(); ++i) {
2656 /* region is moving up, move all regions on intermediate layers
2660 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2661 dest = (*i)->layer() - 1;
2668 /* region is moving down, move all regions on intermediate layers
2672 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2673 dest = (*i)->layer() + 1;
2683 newpair.second = dest;
2685 layerinfo.push_back (newpair);
2691 /* now reset the layers without holding the region lock */
2693 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2694 x->first->set_layer (x->second);
2697 region->set_layer (target_layer);
2699 /* now check all dependents, since we changed the layering */
2701 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2702 check_dependents (x->first, false);
2705 check_dependents (region, false);
2706 notify_layering_changed ();
2714 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2716 RegionList::iterator i;
2722 RegionLock rlock (const_cast<Playlist *> (this));
2724 for (i = regions.begin(); i != regions.end(); ++i) {
2726 if ((*i)->position() >= start) {
2732 if ((*i)->last_frame() > max_framepos - distance) {
2733 new_pos = max_framepos - (*i)->length();
2735 new_pos = (*i)->position() + distance;
2740 if ((*i)->position() > distance) {
2741 new_pos = (*i)->position() - distance;
2747 (*i)->set_position (new_pos, this);
2755 notify_length_changed ();
2760 boost::shared_ptr<Region>
2761 Playlist::find_region (const ID& id) const
2763 RegionLock rlock (const_cast<Playlist*> (this));
2765 /* searches all regions currently in use by the playlist */
2767 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2768 if ((*i)->id() == id) {
2773 return boost::shared_ptr<Region> ();
2777 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2779 RegionLock rlock (const_cast<Playlist*> (this));
2782 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2791 boost::shared_ptr<Region>
2792 Playlist::region_by_id (const ID& id) const
2794 /* searches all regions ever added to this playlist */
2796 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2797 if ((*i)->id() == id) {
2801 return boost::shared_ptr<Region> ();
2805 Playlist::dump () const
2807 boost::shared_ptr<Region> r;
2809 cerr << "Playlist \"" << _name << "\" " << endl
2810 << regions.size() << " regions "
2813 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2815 cerr << " " << r->name() << " ["
2816 << r->start() << "+" << r->length()
2826 Playlist::set_frozen (bool yn)
2832 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2834 region->set_last_layer_op (++layer_op_counter);
2839 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2843 if (region->locked()) {
2850 RegionLock rlock (const_cast<Playlist*> (this));
2855 RegionList::iterator next;
2857 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2858 if ((*i) == region) {
2862 if (next != regions.end()) {
2864 if ((*next)->locked()) {
2870 if ((*next)->position() != region->last_frame() + 1) {
2871 /* they didn't used to touch, so after shuffle,
2872 just have them swap positions.
2874 new_pos = (*next)->position();
2876 /* they used to touch, so after shuffle,
2877 make sure they still do. put the earlier
2878 region where the later one will end after
2881 new_pos = region->position() + (*next)->length();
2884 (*next)->set_position (region->position(), this);
2885 region->set_position (new_pos, this);
2887 /* avoid a full sort */
2889 regions.erase (i); // removes the region from the list */
2891 regions.insert (next, region); // adds it back after next
2900 RegionList::iterator prev = regions.end();
2902 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2903 if ((*i) == region) {
2905 if (prev != regions.end()) {
2907 if ((*prev)->locked()) {
2912 if (region->position() != (*prev)->last_frame() + 1) {
2913 /* they didn't used to touch, so after shuffle,
2914 just have them swap positions.
2916 new_pos = region->position();
2918 /* they used to touch, so after shuffle,
2919 make sure they still do. put the earlier
2920 one where the later one will end after
2922 new_pos = (*prev)->position() + region->length();
2925 region->set_position ((*prev)->position(), this);
2926 (*prev)->set_position (new_pos, this);
2928 /* avoid a full sort */
2930 regions.erase (i); // remove region
2931 regions.insert (prev, region); // insert region before prev
2947 check_dependents (region, false);
2949 notify_contents_changed();
2955 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2957 RegionLock rlock (const_cast<Playlist*> (this));
2959 if (regions.size() > 1) {
2967 Playlist::update_after_tempo_map_change ()
2969 RegionLock rlock (const_cast<Playlist*> (this));
2970 RegionList copy (regions.rlist());
2974 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2975 (*i)->update_position_after_tempo_map_change ();
2982 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2984 RegionLock rl (this, false);
2985 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2991 Playlist::set_explicit_relayering (bool e)
2993 if (e == false && _explicit_relayering == true) {
2995 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2996 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2997 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2998 at this point would keep regions on the same layers.
3000 From then on in, it's just you and your towel.
3003 RegionLock rl (this);
3004 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3005 (*i)->set_last_layer_op ((*i)->layer ());
3009 _explicit_relayering = e;
3014 Playlist::has_region_at (framepos_t const p) const
3016 RegionLock (const_cast<Playlist *> (this));
3018 RegionList::const_iterator i = regions.begin ();
3019 while (i != regions.end() && !(*i)->covers (p)) {
3023 return (i != regions.end());
3026 /** Remove any region that uses a given source */
3028 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
3030 RegionLock rl (this);
3032 RegionList::iterator i = regions.begin();
3033 while (i != regions.end()) {
3034 RegionList::iterator j = i;
3037 if ((*i)->uses_source (s)) {
3038 remove_region_internal (*i);
3045 /** Look from a session frame time and find the start time of the next region
3046 * which is on the top layer of this playlist.
3047 * @param t Time to look from.
3048 * @return Position of next top-layered region, or max_framepos if there isn't one.
3051 Playlist::find_next_top_layer_position (framepos_t t) const
3053 RegionLock rlock (const_cast<Playlist *> (this));
3055 layer_t const top = top_layer ();
3057 RegionList copy = regions.rlist ();
3058 copy.sort (RegionSortByPosition ());
3060 for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3061 if ((*i)->position() >= t && (*i)->layer() == top) {
3062 return (*i)->position();
3066 return max_framepos;