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.
20 #define __STDC_LIMIT_MACROS
31 #include <boost/lexical_cast.hpp>
33 #include "pbd/failed_constructor.h"
34 #include "pbd/stateful_diff_command.h"
35 #include "pbd/xml++.h"
37 #include "ardour/debug.h"
38 #include "ardour/playlist.h"
39 #include "ardour/session.h"
40 #include "ardour/region.h"
41 #include "ardour/region_factory.h"
42 #include "ardour/playlist_factory.h"
43 #include "ardour/transient_detector.h"
44 #include "ardour/session_playlists.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", Properties::regions.property_id));
109 RegionListProperty::RegionListProperty (Playlist& pl)
110 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
117 RegionListProperty::clone () const
119 return new RegionListProperty (*this);
123 RegionListProperty::create () const
125 return new RegionListProperty (_playlist);
129 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
131 /* All regions (even those which are deleted) have their state saved by other
132 code, so we can just store ID here.
135 node.add_property ("id", region->id().to_s ());
138 boost::shared_ptr<Region>
139 RegionListProperty::get_content_from_xml (XMLNode const & node) const
141 XMLProperty const * prop = node.property ("id");
144 PBD::ID id (prop->value ());
146 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
149 ret = RegionFactory::region_by_id (id);
155 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
156 : SessionObject(sess, nom)
161 first_set_state = false;
167 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
168 : SessionObject(sess, "unnamed playlist")
174 const XMLProperty* prop = node.property("type");
175 assert(!prop || DataType(prop->value()) == _type);
179 _name = "unnamed"; /* reset by set_state */
182 /* set state called by derived class */
185 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
186 : SessionObject(other->_session, namestr)
188 , _type(other->_type)
189 , _orig_diskstream_id (other->_orig_diskstream_id)
194 other->copy_regions (tmp);
198 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
199 add_region_internal( (*x), (*x)->position());
204 _splicing = other->_splicing;
205 _nudging = other->_nudging;
206 _edit_mode = other->_edit_mode;
209 first_set_state = false;
211 in_partition = false;
213 _read_data_count = 0;
214 _frozen = other->_frozen;
216 layer_op_counter = other->layer_op_counter;
217 freeze_length = other->freeze_length;
220 Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
221 : SessionObject(other->_session, str)
223 , _type(other->_type)
224 , _orig_diskstream_id (other->_orig_diskstream_id)
226 RegionLock rlock2 (const_cast<Playlist*> (other.get()));
228 framepos_t end = start + cnt - 1;
234 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
236 boost::shared_ptr<Region> region;
237 boost::shared_ptr<Region> new_region;
238 frameoffset_t offset = 0;
239 framepos_t position = 0;
246 overlap = region->coverage (start, end);
252 case OverlapInternal:
253 offset = start - region->position();
260 position = region->position() - start;
261 len = end - region->position();
265 offset = start - region->position();
267 len = region->length() - offset;
270 case OverlapExternal:
272 position = region->position() - start;
273 len = region->length();
277 RegionFactory::region_name (new_name, region->name(), false);
281 plist.add (Properties::start, region->start() + offset);
282 plist.add (Properties::length, len);
283 plist.add (Properties::name, new_name);
284 plist.add (Properties::layer, region->layer());
286 new_region = RegionFactory::RegionFactory::create (region, plist);
288 add_region_internal (new_region, position);
292 first_set_state = false;
294 /* this constructor does NOT notify others (session) */
301 InUse (true); /* EMIT SIGNAL */
312 InUse (false); /* EMIT SIGNAL */
317 Playlist::copy_regions (RegionList& newlist) const
319 RegionLock rlock (const_cast<Playlist *> (this));
321 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
322 newlist.push_back (RegionFactory::RegionFactory::create (*i));
327 Playlist::init (bool hide)
329 add_property (regions);
330 _xml_node_name = X_("Playlist");
332 g_atomic_int_set (&block_notifications, 0);
333 g_atomic_int_set (&ignore_state_changes, 0);
334 pending_contents_change = false;
335 pending_length = false;
336 pending_layering = false;
337 first_set_state = true;
345 _edit_mode = Config->get_edit_mode();
347 in_partition = false;
349 _read_data_count = 0;
351 layer_op_counter = 0;
353 _explicit_relayering = false;
355 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
356 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
358 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
361 Playlist::~Playlist ()
363 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
366 RegionLock rl (this);
368 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
369 (*i)->set_playlist (boost::shared_ptr<Playlist>());
373 /* GoingAway must be emitted by derived classes */
377 Playlist::_set_sort_id ()
380 Playlists are given names like <track name>.<id>
381 or <track name>.<edit group name>.<id> where id
382 is an integer. We extract the id and sort by that.
385 size_t dot_position = _name.val().find_last_of(".");
387 if (dot_position == string::npos) {
390 string t = _name.val().substr(dot_position + 1);
393 _sort_id = boost::lexical_cast<int>(t);
396 catch (boost::bad_lexical_cast e) {
403 Playlist::set_name (const string& str)
405 /* in a typical situation, a playlist is being used
406 by one diskstream and also is referenced by the
407 Session. if there are more references than that,
408 then don't change the name.
415 bool ret = SessionObject::set_name(str);
422 /***********************************************************************
423 CHANGE NOTIFICATION HANDLING
425 Notifications must be delayed till the region_lock is released. This
426 is necessary because handlers for the signals may need to acquire
427 the lock (e.g. to read from the playlist).
428 ***********************************************************************/
431 Playlist::begin_undo ()
438 Playlist::end_undo ()
447 delay_notifications ();
448 g_atomic_int_inc (&ignore_state_changes);
451 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
453 Playlist::thaw (bool from_undo)
455 g_atomic_int_dec_and_test (&ignore_state_changes);
456 release_notifications (from_undo);
461 Playlist::delay_notifications ()
463 g_atomic_int_inc (&block_notifications);
464 freeze_length = _get_extent().second;
467 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
469 Playlist::release_notifications (bool from_undo)
471 if (g_atomic_int_dec_and_test (&block_notifications)) {
472 flush_notifications (from_undo);
478 Playlist::notify_contents_changed ()
480 if (holding_state ()) {
481 pending_contents_change = true;
483 pending_contents_change = false;
484 ContentsChanged(); /* EMIT SIGNAL */
489 Playlist::notify_layering_changed ()
491 if (holding_state ()) {
492 pending_layering = true;
494 pending_layering = false;
495 LayeringChanged(); /* EMIT SIGNAL */
500 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
502 if (holding_state ()) {
503 pending_removes.insert (r);
504 pending_contents_change = true;
505 pending_length = true;
507 /* this might not be true, but we have to act
508 as though it could be.
510 pending_length = false;
511 LengthChanged (); /* EMIT SIGNAL */
512 pending_contents_change = false;
513 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
514 ContentsChanged (); /* EMIT SIGNAL */
519 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
521 Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
523 if (holding_state ()) {
525 pending_range_moves.push_back (move);
529 list< Evoral::RangeMove<framepos_t> > m;
531 RangesMoved (m, false);
537 Playlist::notify_region_added (boost::shared_ptr<Region> r)
539 /* the length change might not be true, but we have to act
540 as though it could be.
543 if (holding_state()) {
544 pending_adds.insert (r);
545 pending_contents_change = true;
546 pending_length = true;
549 pending_length = false;
550 LengthChanged (); /* EMIT SIGNAL */
551 pending_contents_change = false;
552 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
553 ContentsChanged (); /* EMIT SIGNAL */
558 Playlist::notify_length_changed ()
560 if (holding_state ()) {
561 pending_length = true;
563 pending_length = false;
564 LengthChanged(); /* EMIT SIGNAL */
565 pending_contents_change = false;
566 ContentsChanged (); /* EMIT SIGNAL */
570 /** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
572 Playlist::flush_notifications (bool from_undo)
574 set<boost::shared_ptr<Region> > dependent_checks_needed;
575 set<boost::shared_ptr<Region> >::iterator s;
576 uint32_t regions_changed = false;
577 bool check_length = false;
578 framecnt_t old_length = 0;
586 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
587 regions_changed = true;
588 if (!pending_length) {
589 old_length = _get_extent ().second;
594 /* we have no idea what order the regions ended up in pending
595 bounds (it could be based on selection order, for example).
596 so, to preserve layering in the "most recently moved is higher"
597 model, sort them by existing layer, then timestamp them.
600 // RegionSortByLayer cmp;
601 // pending_bounds.sort (cmp);
603 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
604 if (_session.config.get_layer_model() == MoveAddHigher) {
605 timestamp_layer_op (*r);
607 dependent_checks_needed.insert (*r);
610 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
611 remove_dependents (*s);
612 // cerr << _name << " sends RegionRemoved\n";
613 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
616 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
617 // cerr << _name << " sends RegionAdded\n";
618 /* don't emit RegionAdded signal until relayering is done,
619 so that the region is fully setup by the time
620 anyone hear's that its been added
622 dependent_checks_needed.insert (*s);
626 if (old_length != _get_extent().second) {
627 pending_length = true;
628 // cerr << _name << " length has changed\n";
632 if (pending_length || (freeze_length != _get_extent().second)) {
633 pending_length = false;
634 // cerr << _name << " sends LengthChanged\n";
635 LengthChanged(); /* EMIT SIGNAL */
638 if (regions_changed || pending_contents_change) {
642 pending_contents_change = false;
643 // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
644 ContentsChanged (); /* EMIT SIGNAL */
645 // cerr << _name << "done contents change @ " << get_microseconds() << endl;
648 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
649 (*s)->clear_changes ();
650 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
653 for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
654 check_dependents (*s, false);
657 if (!pending_range_moves.empty ()) {
658 RangesMoved (pending_range_moves, from_undo);
667 Playlist::clear_pending ()
669 pending_adds.clear ();
670 pending_removes.clear ();
671 pending_bounds.clear ();
672 pending_range_moves.clear ();
673 pending_contents_change = false;
674 pending_length = false;
677 /*************************************************************
679 *************************************************************/
682 Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
684 RegionLock rlock (this);
685 times = fabs (times);
687 int itimes = (int) floor (times);
689 framepos_t pos = position;
691 if (times == 1 && auto_partition){
692 partition(pos - 1, (pos + region->length()), true);
696 add_region_internal (region, pos);
697 pos += region->length();
702 /* note that itimes can be zero if we being asked to just
703 insert a single fraction of the region.
706 for (int i = 0; i < itimes; ++i) {
707 boost::shared_ptr<Region> copy = RegionFactory::create (region);
708 add_region_internal (copy, pos);
709 pos += region->length();
712 framecnt_t length = 0;
714 if (floor (times) != times) {
715 length = (framecnt_t) floor (region->length() * (times - floor (times)));
717 RegionFactory::region_name (name, region->name(), false);
722 plist.add (Properties::start, region->start());
723 plist.add (Properties::length, length);
724 plist.add (Properties::name, name);
725 plist.add (Properties::layer, region->layer());
727 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
728 add_region_internal (sub, pos);
732 possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
736 Playlist::set_region_ownership ()
738 RegionLock rl (this);
739 RegionList::iterator i;
740 boost::weak_ptr<Playlist> pl (shared_from_this());
742 for (i = regions.begin(); i != regions.end(); ++i) {
743 (*i)->set_playlist (pl);
748 Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
750 if (region->data_type() != _type){
754 RegionSortByPosition cmp;
756 framecnt_t old_length = 0;
758 if (!holding_state()) {
759 old_length = _get_extent().second;
762 if (!first_set_state) {
763 boost::shared_ptr<Playlist> foo (shared_from_this());
764 region->set_playlist (boost::weak_ptr<Playlist>(foo));
767 region->set_position (position, this);
769 timestamp_layer_op (region);
771 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
772 all_regions.insert (region);
774 possibly_splice_unlocked (position, region->length(), region);
776 if (!holding_state ()) {
777 /* layers get assigned from XML state, and are not reset during undo/redo */
781 /* we need to notify the existence of new region before checking dependents. Ick. */
783 notify_region_added (region);
785 if (!holding_state ()) {
787 check_dependents (region, false);
789 if (old_length != _get_extent().second) {
790 notify_length_changed ();
794 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
800 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
802 RegionLock rlock (this);
804 bool old_sp = _splicing;
807 remove_region_internal (old);
808 add_region_internal (newr, pos);
812 possibly_splice_unlocked (pos, old->length() - newr->length());
816 Playlist::remove_region (boost::shared_ptr<Region> region)
818 RegionLock rlock (this);
819 remove_region_internal (region);
823 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
825 RegionList::iterator i;
826 framecnt_t old_length = 0;
829 if (!holding_state()) {
830 old_length = _get_extent().second;
835 region->set_playlist (boost::weak_ptr<Playlist>());
838 /* XXX should probably freeze here .... */
840 for (i = regions.begin(); i != regions.end(); ++i) {
843 framepos_t pos = (*i)->position();
844 framecnt_t distance = (*i)->length();
848 possibly_splice_unlocked (pos, -distance);
850 if (!holding_state ()) {
852 remove_dependents (region);
854 if (old_length != _get_extent().second) {
855 notify_length_changed ();
859 notify_region_removed (region);
869 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
871 if (Config->get_use_overlap_equivalency()) {
872 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
873 if ((*i)->overlap_equivalent (other)) {
874 results.push_back ((*i));
878 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
879 if ((*i)->equivalent (other)) {
880 results.push_back ((*i));
887 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
889 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
891 if ((*i) && (*i)->region_list_equivalent (other)) {
892 results.push_back (*i);
898 Playlist::partition (framepos_t start, framepos_t end, bool cut)
902 partition_internal (start, end, cut, thawlist);
904 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
905 (*i)->resume_property_changes ();
910 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
912 RegionList new_regions;
915 RegionLock rlock (this);
917 boost::shared_ptr<Region> region;
918 boost::shared_ptr<Region> current;
920 RegionList::iterator tmp;
922 framepos_t pos1, pos2, pos3, pos4;
926 /* need to work from a copy, because otherwise the regions we add during the process
927 get operated on as well.
930 RegionList copy = regions.rlist();
932 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
939 if (current->first_frame() >= start && current->last_frame() < end) {
942 remove_region_internal (current);
948 /* coverage will return OverlapStart if the start coincides
949 with the end point. we do not partition such a region,
950 so catch this special case.
953 if (current->first_frame() >= end) {
957 if ((overlap = current->coverage (start, end)) == OverlapNone) {
961 pos1 = current->position();
964 pos4 = current->last_frame();
966 if (overlap == OverlapInternal) {
967 /* split: we need 3 new regions, the front, middle and end.
968 cut: we need 2 regions, the front and end.
973 ---------------*************************------------
976 ---------------*****++++++++++++++++====------------
978 ---------------*****----------------====------------
983 /* "middle" ++++++ */
985 RegionFactory::region_name (new_name, current->name(), false);
989 plist.add (Properties::start, current->start() + (pos2 - pos1));
990 plist.add (Properties::length, pos3 - pos2);
991 plist.add (Properties::name, new_name);
992 plist.add (Properties::layer, regions.size());
993 plist.add (Properties::automatic, true);
994 plist.add (Properties::left_of_split, true);
995 plist.add (Properties::right_of_split, true);
997 region = RegionFactory::create (current, plist);
998 add_region_internal (region, start);
999 new_regions.push_back (region);
1004 RegionFactory::region_name (new_name, current->name(), false);
1008 plist.add (Properties::start, current->start() + (pos3 - pos1));
1009 plist.add (Properties::length, pos4 - pos3);
1010 plist.add (Properties::name, new_name);
1011 plist.add (Properties::layer, regions.size());
1012 plist.add (Properties::automatic, true);
1013 plist.add (Properties::right_of_split, true);
1015 region = RegionFactory::create (current, plist);
1017 add_region_internal (region, end);
1018 new_regions.push_back (region);
1022 current->suspend_property_changes ();
1023 thawlist.push_back (current);
1024 current->cut_end (pos2 - 1, this);
1026 } else if (overlap == OverlapEnd) {
1030 ---------------*************************------------
1033 ---------------**************+++++++++++------------
1035 ---------------**************-----------------------
1042 RegionFactory::region_name (new_name, current->name(), false);
1046 plist.add (Properties::start, current->start() + (pos2 - pos1));
1047 plist.add (Properties::length, pos4 - pos2);
1048 plist.add (Properties::name, new_name);
1049 plist.add (Properties::layer, regions.size());
1050 plist.add (Properties::automatic, true);
1051 plist.add (Properties::left_of_split, true);
1053 region = RegionFactory::create (current, plist);
1055 add_region_internal (region, start);
1056 new_regions.push_back (region);
1061 current->suspend_property_changes ();
1062 thawlist.push_back (current);
1063 current->cut_end (pos2 - 1, this);
1065 } else if (overlap == OverlapStart) {
1067 /* split: we need 2 regions: the front and the end.
1068 cut: just trim current to skip the cut area
1073 ---------------*************************------------
1077 ---------------****+++++++++++++++++++++------------
1079 -------------------*********************------------
1085 RegionFactory::region_name (new_name, current->name(), false);
1089 plist.add (Properties::start, current->start());
1090 plist.add (Properties::length, pos3 - pos1);
1091 plist.add (Properties::name, new_name);
1092 plist.add (Properties::layer, regions.size());
1093 plist.add (Properties::automatic, true);
1094 plist.add (Properties::right_of_split, true);
1096 region = RegionFactory::create (current, plist);
1098 add_region_internal (region, pos1);
1099 new_regions.push_back (region);
1104 current->suspend_property_changes ();
1105 thawlist.push_back (current);
1106 current->trim_front (pos3, this);
1107 } else if (overlap == OverlapExternal) {
1109 /* split: no split required.
1110 cut: remove the region.
1115 ---------------*************************------------
1119 ---------------*************************------------
1121 ----------------------------------------------------
1126 remove_region_internal (current);
1129 new_regions.push_back (current);
1133 in_partition = false;
1136 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1137 check_dependents (*i, false);
1141 boost::shared_ptr<Playlist>
1142 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1144 boost::shared_ptr<Playlist> ret;
1145 boost::shared_ptr<Playlist> pl;
1148 if (ranges.empty()) {
1149 return boost::shared_ptr<Playlist>();
1152 start = ranges.front().start;
1154 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1156 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1158 if (i == ranges.begin()) {
1162 /* paste the next section into the nascent playlist,
1163 offset to reflect the start of the first range we
1167 ret->paste (pl, (*i).start - start, 1.0f);
1174 boost::shared_ptr<Playlist>
1175 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1177 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1178 return cut_copy (pmf, ranges, result_is_hidden);
1181 boost::shared_ptr<Playlist>
1182 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1184 boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1185 return cut_copy (pmf, ranges, result_is_hidden);
1188 boost::shared_ptr<Playlist>
1189 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1191 boost::shared_ptr<Playlist> the_copy;
1192 RegionList thawlist;
1195 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1196 string new_name = _name;
1200 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1201 return boost::shared_ptr<Playlist>();
1204 partition_internal (start, start+cnt-1, true, thawlist);
1206 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1207 (*i)->resume_property_changes();
1213 boost::shared_ptr<Playlist>
1214 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1218 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1219 string new_name = _name;
1223 cnt = min (_get_extent().second - start, cnt);
1224 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1228 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1230 times = fabs (times);
1233 RegionLock rl1 (this);
1234 RegionLock rl2 (other.get());
1236 framecnt_t const old_length = _get_extent().second;
1238 int itimes = (int) floor (times);
1239 framepos_t pos = position;
1240 framecnt_t const shift = other->_get_extent().second;
1241 layer_t top_layer = regions.size();
1244 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1245 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
1247 /* put these new regions on top of all existing ones, but preserve
1248 the ordering they had in the original playlist.
1251 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1252 add_region_internal (copy_of_region, copy_of_region->position() + pos);
1258 /* XXX shall we handle fractional cases at some point? */
1260 if (old_length != _get_extent().second) {
1261 notify_length_changed ();
1272 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1274 times = fabs (times);
1276 RegionLock rl (this);
1277 int itimes = (int) floor (times);
1278 framepos_t pos = position + 1;
1281 boost::shared_ptr<Region> copy = RegionFactory::create (region);
1282 add_region_internal (copy, pos);
1283 pos += region->length();
1286 if (floor (times) != times) {
1287 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1289 RegionFactory::region_name (name, region->name(), false);
1294 plist.add (Properties::start, region->start());
1295 plist.add (Properties::length, length);
1296 plist.add (Properties::name, name);
1298 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1299 add_region_internal (sub, pos);
1305 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1307 RegionLock rlock (this);
1308 RegionList copy (regions.rlist());
1311 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1313 if ((*r)->last_frame() < at) {
1318 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1319 /* intersected region */
1320 if (!move_intersected) {
1325 /* do not move regions glued to music time - that
1326 has to be done separately.
1329 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1330 fixup.push_back (*r);
1334 (*r)->set_position ((*r)->position() + distance, this);
1337 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1338 (*r)->recompute_position_from_lock_style ();
1343 Playlist::split (framepos_t at)
1345 RegionLock rlock (this);
1346 RegionList copy (regions.rlist());
1348 /* use a copy since this operation can modify the region list
1351 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1352 _split_region (*r, at);
1357 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1359 RegionLock rl (this);
1360 _split_region (region, playlist_position);
1364 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1366 if (!region->covers (playlist_position)) {
1370 if (region->position() == playlist_position ||
1371 region->last_frame() == playlist_position) {
1375 boost::shared_ptr<Region> left;
1376 boost::shared_ptr<Region> right;
1377 frameoffset_t before;
1378 frameoffset_t after;
1382 /* split doesn't change anything about length, so don't try to splice */
1384 bool old_sp = _splicing;
1387 before = playlist_position - region->position();
1388 after = region->length() - before;
1390 RegionFactory::region_name (before_name, region->name(), false);
1395 plist.add (Properties::length, before);
1396 plist.add (Properties::name, before_name);
1397 plist.add (Properties::left_of_split, true);
1399 /* note: we must use the version of ::create with an offset here,
1400 since it supplies that offset to the Region constructor, which
1401 is necessary to get audio region gain envelopes right.
1403 left = RegionFactory::create (region, 0, plist);
1406 RegionFactory::region_name (after_name, region->name(), false);
1411 plist.add (Properties::length, after);
1412 plist.add (Properties::name, after_name);
1413 plist.add (Properties::right_of_split, true);
1415 /* same note as above */
1416 right = RegionFactory::create (region, before, plist);
1419 add_region_internal (left, region->position());
1420 add_region_internal (right, region->position() + before);
1422 uint64_t orig_layer_op = region->last_layer_op();
1423 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1424 if ((*i)->last_layer_op() > orig_layer_op) {
1425 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1429 left->set_last_layer_op ( orig_layer_op );
1430 right->set_last_layer_op ( orig_layer_op + 1);
1434 finalize_split_region (region, left, right);
1436 remove_region_internal (region);
1442 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1444 if (_splicing || in_set_state) {
1445 /* don't respond to splicing moves or state setting */
1449 if (_edit_mode == Splice) {
1450 splice_locked (at, distance, exclude);
1455 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1457 if (_splicing || in_set_state) {
1458 /* don't respond to splicing moves or state setting */
1462 if (_edit_mode == Splice) {
1463 splice_unlocked (at, distance, exclude);
1468 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1471 RegionLock rl (this);
1472 core_splice (at, distance, exclude);
1477 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1479 core_splice (at, distance, exclude);
1483 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1487 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1489 if (exclude && (*i) == exclude) {
1493 if ((*i)->position() >= at) {
1494 framepos_t new_pos = (*i)->position() + distance;
1497 } else if (new_pos >= max_frames - (*i)->length()) {
1498 new_pos = max_frames - (*i)->length();
1501 (*i)->set_position (new_pos, this);
1507 notify_length_changed ();
1511 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1513 if (in_set_state || _splicing || _nudging || _shuffling) {
1517 if (what_changed.contains (Properties::position)) {
1519 /* remove it from the list then add it back in
1520 the right place again.
1523 RegionSortByPosition cmp;
1525 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1527 if (i == regions.end()) {
1528 /* the region bounds are being modified but its not currently
1529 in the region list. we will use its bounds correctly when/if
1536 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1539 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1541 frameoffset_t delta = 0;
1543 if (what_changed.contains (Properties::position)) {
1544 delta = region->position() - region->last_position();
1547 if (what_changed.contains (Properties::length)) {
1548 delta += region->length() - region->last_length();
1552 possibly_splice (region->last_position() + region->last_length(), delta, region);
1555 if (holding_state ()) {
1556 pending_bounds.push_back (region);
1558 if (_session.config.get_layer_model() == MoveAddHigher) {
1559 /* it moved or changed length, so change the timestamp */
1560 timestamp_layer_op (region);
1563 notify_length_changed ();
1565 check_dependents (region, false);
1571 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1573 boost::shared_ptr<Region> region (weak_region.lock());
1579 /* this makes a virtual call to the right kind of playlist ... */
1581 region_changed (what_changed, region);
1585 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1587 PropertyChange our_interests;
1588 PropertyChange bounds;
1589 PropertyChange pos_and_length;
1592 if (in_set_state || in_flush) {
1596 our_interests.add (Properties::muted);
1597 our_interests.add (Properties::layer);
1598 our_interests.add (Properties::opaque);
1600 bounds.add (Properties::start);
1601 bounds.add (Properties::position);
1602 bounds.add (Properties::length);
1604 pos_and_length.add (Properties::position);
1605 pos_and_length.add (Properties::length);
1607 if (what_changed.contains (bounds)) {
1608 region_bounds_changed (what_changed, region);
1609 save = !(_splicing || _nudging);
1612 if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1613 check_dependents (region, false);
1616 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1617 notify_region_moved (region);
1621 /* don't notify about layer changes, since we are the only object that can initiate
1622 them, and we notify in ::relayer()
1625 if (what_changed.contains (our_interests)) {
1633 Playlist::drop_regions ()
1635 RegionLock rl (this);
1637 all_regions.clear ();
1641 Playlist::clear (bool with_signals)
1644 RegionLock rl (this);
1646 region_state_changed_connections.drop_connections ();
1648 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1649 pending_removes.insert (*i);
1654 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1655 remove_dependents (*s);
1661 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1662 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1665 pending_removes.clear ();
1666 pending_length = false;
1668 pending_contents_change = false;
1674 /***********************************************************************
1676 **********************************************************************/
1678 Playlist::RegionList *
1679 Playlist::regions_at (framepos_t frame)
1682 RegionLock rlock (this);
1683 return find_regions_at (frame);
1687 Playlist::count_regions_at (framepos_t frame)
1689 RegionLock rlock (this);
1692 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1693 if ((*i)->covers (frame)) {
1701 boost::shared_ptr<Region>
1702 Playlist::top_region_at (framepos_t frame)
1705 RegionLock rlock (this);
1706 RegionList *rlist = find_regions_at (frame);
1707 boost::shared_ptr<Region> region;
1709 if (rlist->size()) {
1710 RegionSortByLayer cmp;
1712 region = rlist->back();
1719 boost::shared_ptr<Region>
1720 Playlist::top_unmuted_region_at (framepos_t frame)
1723 RegionLock rlock (this);
1724 RegionList *rlist = find_regions_at (frame);
1726 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1728 RegionList::iterator tmp = i;
1731 if ((*i)->muted()) {
1738 boost::shared_ptr<Region> region;
1740 if (rlist->size()) {
1741 RegionSortByLayer cmp;
1743 region = rlist->back();
1750 Playlist::RegionList*
1751 Playlist::regions_to_read (framepos_t start, framepos_t end)
1753 /* Caller must hold lock */
1755 RegionList covering;
1756 set<framepos_t> to_check;
1757 set<boost::shared_ptr<Region> > unique;
1759 to_check.insert (start);
1760 to_check.insert (end);
1762 DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1764 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1766 /* find all/any regions that span start+end */
1768 switch ((*i)->coverage (start, end)) {
1772 case OverlapInternal:
1773 covering.push_back (*i);
1774 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1778 to_check.insert ((*i)->position());
1779 if ((*i)->position() != 0) {
1780 to_check.insert ((*i)->position()-1);
1782 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1783 covering.push_back (*i);
1787 to_check.insert ((*i)->last_frame());
1788 to_check.insert ((*i)->last_frame()+1);
1789 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1790 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1791 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1792 covering.push_back (*i);
1795 case OverlapExternal:
1796 covering.push_back (*i);
1797 to_check.insert ((*i)->position());
1798 if ((*i)->position() != 0) {
1799 to_check.insert ((*i)->position()-1);
1801 to_check.insert ((*i)->last_frame());
1802 to_check.insert ((*i)->last_frame()+1);
1803 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1804 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1805 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1809 /* don't go too far */
1811 if ((*i)->position() > end) {
1816 RegionList* rlist = new RegionList;
1818 /* find all the regions that cover each position .... */
1820 if (covering.size() == 1) {
1822 rlist->push_back (covering.front());
1823 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1828 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1832 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1834 for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1836 if ((*x)->covers (*t)) {
1837 here.push_back (*x);
1838 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1842 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1849 RegionSortByLayer cmp;
1852 /* ... and get the top/transparent regions at "here" */
1854 for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1858 if ((*c)->opaque()) {
1860 /* the other regions at this position are hidden by this one */
1861 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1868 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1869 rlist->push_back (*s);
1872 if (rlist->size() > 1) {
1873 /* now sort by time order */
1875 RegionSortByPosition cmp;
1880 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1885 Playlist::RegionList *
1886 Playlist::find_regions_at (framepos_t frame)
1888 /* Caller must hold lock */
1890 RegionList *rlist = new RegionList;
1892 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1893 if ((*i)->covers (frame)) {
1894 rlist->push_back (*i);
1901 Playlist::RegionList *
1902 Playlist::regions_touched (framepos_t start, framepos_t end)
1904 RegionLock rlock (this);
1905 RegionList *rlist = new RegionList;
1907 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1908 if ((*i)->coverage (start, end) != OverlapNone) {
1909 rlist->push_back (*i);
1917 Playlist::find_next_transient (framepos_t from, int dir)
1919 RegionLock rlock (this);
1920 AnalysisFeatureList points;
1921 AnalysisFeatureList these_points;
1923 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1925 if ((*i)->last_frame() < from) {
1929 if ((*i)->first_frame() > from) {
1934 (*i)->get_transients (these_points);
1936 /* add first frame, just, err, because */
1938 these_points.push_back ((*i)->first_frame());
1940 points.insert (points.end(), these_points.begin(), these_points.end());
1941 these_points.clear ();
1944 if (points.empty()) {
1948 TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1949 bool reached = false;
1952 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1957 if (reached && (*x) > from) {
1962 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1967 if (reached && (*x) < from) {
1976 boost::shared_ptr<Region>
1977 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1979 RegionLock rlock (this);
1980 boost::shared_ptr<Region> ret;
1981 framepos_t closest = max_frames;
1983 bool end_iter = false;
1985 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1989 frameoffset_t distance;
1990 boost::shared_ptr<Region> r = (*i);
1995 pos = r->first_frame ();
1998 pos = r->last_frame ();
2001 pos = r->sync_position ();
2006 case 1: /* forwards */
2009 if ((distance = pos - frame) < closest) {
2018 default: /* backwards */
2021 if ((distance = frame - pos) < closest) {
2038 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2040 RegionLock rlock (this);
2042 framepos_t closest = max_frames;
2043 framepos_t ret = -1;
2047 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2049 boost::shared_ptr<Region> r = (*i);
2050 frameoffset_t distance;
2052 if (r->first_frame() > frame) {
2054 distance = r->first_frame() - frame;
2056 if (distance < closest) {
2057 ret = r->first_frame();
2062 if (r->last_frame () > frame) {
2064 distance = r->last_frame () - frame;
2066 if (distance < closest) {
2067 ret = r->last_frame ();
2075 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2077 boost::shared_ptr<Region> r = (*i);
2078 frameoffset_t distance;
2080 if (r->last_frame() < frame) {
2082 distance = frame - r->last_frame();
2084 if (distance < closest) {
2085 ret = r->last_frame();
2090 if (r->first_frame() < frame) {
2092 distance = frame - r->first_frame();
2094 if (distance < closest) {
2095 ret = r->first_frame();
2106 /***********************************************************************/
2112 Playlist::mark_session_dirty ()
2114 if (!in_set_state && !holding_state ()) {
2115 _session.set_dirty();
2120 Playlist::rdiff (vector<Command*>& cmds) const
2122 RegionLock rlock (const_cast<Playlist *> (this));
2123 Stateful::rdiff (cmds);
2127 Playlist::clear_owned_changes ()
2129 RegionLock rlock (this);
2130 Stateful::clear_owned_changes ();
2134 Playlist::update (const RegionListProperty::ChangeRecord& change)
2136 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2137 name(), change.added.size(), change.removed.size()));
2140 /* add the added regions */
2141 for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2142 add_region ((*i), (*i)->position());
2144 /* remove the removed regions */
2145 for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2153 Playlist::set_state (const XMLNode& node, int version)
2157 XMLNodeConstIterator niter;
2158 XMLPropertyList plist;
2159 XMLPropertyConstIterator piter;
2161 boost::shared_ptr<Region> region;
2166 if (node.name() != "Playlist") {
2173 plist = node.properties();
2175 for (piter = plist.begin(); piter != plist.end(); ++piter) {
2179 if (prop->name() == X_("name")) {
2180 _name = prop->value();
2182 } else if (prop->name() == X_("id")) {
2183 _id = prop->value();
2184 } else if (prop->name() == X_("orig_diskstream_id")) {
2185 _orig_diskstream_id = prop->value ();
2186 } else if (prop->name() == X_("frozen")) {
2187 _frozen = string_is_affirmative (prop->value());
2193 nlist = node.children();
2195 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2199 if (child->name() == "Region") {
2201 if ((prop = child->property ("id")) == 0) {
2202 error << _("region state node has no ID, ignored") << endmsg;
2206 ID id = prop->value ();
2208 if ((region = region_by_id (id))) {
2210 region->suspend_property_changes ();
2212 if (region->set_state (*child, version)) {
2213 region->resume_property_changes ();
2217 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2218 region->suspend_property_changes ();
2220 error << _("Playlist: cannot create region from XML") << endmsg;
2225 add_region (region, region->position(), 1.0);
2227 // So that layer_op ordering doesn't get screwed up
2228 region->set_last_layer_op( region->layer());
2229 region->resume_property_changes ();
2233 /* update dependents, which was not done during add_region_internal
2234 due to in_set_state being true
2237 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2238 check_dependents (*r, false);
2242 notify_contents_changed ();
2245 first_set_state = false;
2250 Playlist::get_state()
2252 return state (true);
2256 Playlist::get_template()
2258 return state (false);
2261 /** @param full_state true to include regions in the returned state, otherwise false.
2264 Playlist::state (bool full_state)
2266 XMLNode *node = new XMLNode (X_("Playlist"));
2269 node->add_property (X_("id"), id().to_s());
2270 node->add_property (X_("name"), _name);
2271 node->add_property (X_("type"), _type.to_string());
2273 _orig_diskstream_id.print (buf, sizeof (buf));
2274 node->add_property (X_("orig_diskstream_id"), buf);
2275 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2278 RegionLock rlock (this, false);
2280 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2281 node->add_child_nocopy ((*i)->get_state());
2286 node->add_child_copy (*_extra_xml);
2293 Playlist::empty() const
2295 RegionLock rlock (const_cast<Playlist *>(this), false);
2296 return regions.empty();
2300 Playlist::n_regions() const
2302 RegionLock rlock (const_cast<Playlist *>(this), false);
2303 return regions.size();
2306 pair<framecnt_t, framecnt_t>
2307 Playlist::get_extent () const
2309 RegionLock rlock (const_cast<Playlist *>(this), false);
2310 return _get_extent ();
2313 pair<framecnt_t, framecnt_t>
2314 Playlist::_get_extent () const
2316 pair<framecnt_t, framecnt_t> ext (max_frames, 0);
2318 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2319 pair<framecnt_t, framecnt_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2320 if (e.first < ext.first) {
2321 ext.first = e.first;
2323 if (e.second > ext.second) {
2324 ext.second = e.second;
2332 Playlist::bump_name (string name, Session &session)
2334 string newname = name;
2337 newname = bump_name_once (newname, '.');
2338 } while (session.playlists->by_name (newname)!=NULL);
2345 Playlist::top_layer() const
2347 RegionLock rlock (const_cast<Playlist *> (this));
2350 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2351 top = max (top, (*i)->layer());
2357 Playlist::set_edit_mode (EditMode mode)
2362 /********************
2364 ********************/
2367 Playlist::relayer ()
2369 /* never compute layers when changing state for undo/redo or setting from XML */
2371 if (in_update || in_set_state) {
2375 bool changed = false;
2377 /* Build up a new list of regions on each layer, stored in a set of lists
2378 each of which represent some period of time on some layer. The idea
2379 is to avoid having to search the entire region list to establish whether
2380 each region overlaps another */
2382 /* how many pieces to divide this playlist's time up into */
2383 int const divisions = 512;
2385 /* find the start and end positions of the regions on this playlist */
2386 framepos_t start = INT64_MAX;
2388 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2389 start = min (start, (*i)->position());
2390 end = max (end, (*i)->position() + (*i)->length());
2393 /* hence the size of each time division */
2394 double const division_size = (end - start) / double (divisions);
2396 vector<vector<RegionList> > layers;
2397 layers.push_back (vector<RegionList> (divisions));
2399 /* we want to go through regions from desired lowest to desired highest layer,
2400 which depends on the layer model
2403 RegionList copy = regions.rlist();
2405 /* sort according to the model and the layering mode that we're in */
2407 if (_explicit_relayering) {
2409 copy.sort (RegionSortByLayerWithPending ());
2411 } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2413 copy.sort (RegionSortByLastLayerOp ());
2418 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2420 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2421 (*i)->set_pending_explicit_relayer (false);
2423 /* find the time divisions that this region covers; if there are no regions on the list,
2424 division_size will equal 0 and in this case we'll just say that
2425 start_division = end_division = 0.
2427 int start_division = 0;
2428 int end_division = 0;
2430 if (division_size > 0) {
2431 start_division = floor ( ((*i)->position() - start) / division_size);
2432 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2433 if (end_division == divisions) {
2438 assert (divisions == 0 || end_division < divisions);
2440 /* find the lowest layer that this region can go on */
2441 size_t j = layers.size();
2443 /* try layer j - 1; it can go on if it overlaps no other region
2444 that is already on that layer
2447 bool overlap = false;
2448 for (int k = start_division; k <= end_division; ++k) {
2449 RegionList::iterator l = layers[j-1][k].begin ();
2450 while (l != layers[j-1][k].end()) {
2451 if ((*l)->overlap_equivalent (*i)) {
2464 /* overlap, so we must use layer j */
2471 if (j == layers.size()) {
2472 /* we need a new layer for this region */
2473 layers.push_back (vector<RegionList> (divisions));
2476 /* put a reference to this region in each of the divisions that it exists in */
2477 for (int k = start_division; k <= end_division; ++k) {
2478 layers[j][k].push_back (*i);
2481 if ((*i)->layer() != j) {
2485 (*i)->set_layer (j);
2489 notify_layering_changed ();
2493 /* XXX these layer functions are all deprecated */
2496 Playlist::raise_region (boost::shared_ptr<Region> region)
2498 uint32_t top = regions.size() - 1;
2499 layer_t target = region->layer() + 1U;
2501 if (target >= top) {
2502 /* its already at the effective top */
2506 move_region_to_layer (target, region, 1);
2510 Playlist::lower_region (boost::shared_ptr<Region> region)
2512 if (region->layer() == 0) {
2513 /* its already at the bottom */
2517 layer_t target = region->layer() - 1U;
2519 move_region_to_layer (target, region, -1);
2523 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2525 /* does nothing useful if layering mode is later=higher */
2526 switch (_session.config.get_layer_model()) {
2533 layer_t top = regions.size() - 1;
2535 if (region->layer() >= top) {
2536 /* already on the top */
2540 move_region_to_layer (top, region, 1);
2541 /* mark the region's last_layer_op as now, so that it remains on top when
2542 doing future relayers (until something else takes over)
2544 timestamp_layer_op (region);
2548 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2550 /* does nothing useful if layering mode is later=higher */
2551 switch (_session.config.get_layer_model()) {
2558 if (region->layer() == 0) {
2559 /* already on the bottom */
2563 move_region_to_layer (0, region, -1);
2564 /* force region's last layer op to zero so that it stays at the bottom
2565 when doing future relayers
2567 region->set_last_layer_op (0);
2571 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2573 RegionList::iterator i;
2574 typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2575 list<LayerInfo> layerinfo;
2578 RegionLock rlock (const_cast<Playlist *> (this));
2580 for (i = regions.begin(); i != regions.end(); ++i) {
2590 /* region is moving up, move all regions on intermediate layers
2594 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2595 dest = (*i)->layer() - 1;
2602 /* region is moving down, move all regions on intermediate layers
2606 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2607 dest = (*i)->layer() + 1;
2617 newpair.second = dest;
2619 layerinfo.push_back (newpair);
2625 /* now reset the layers without holding the region lock */
2627 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2628 x->first->set_layer (x->second);
2631 region->set_layer (target_layer);
2633 /* now check all dependents, since we changed the layering */
2635 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2636 check_dependents (x->first, false);
2639 check_dependents (region, false);
2640 notify_layering_changed ();
2648 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2650 RegionList::iterator i;
2656 RegionLock rlock (const_cast<Playlist *> (this));
2658 for (i = regions.begin(); i != regions.end(); ++i) {
2660 if ((*i)->position() >= start) {
2666 if ((*i)->last_frame() > max_frames - distance) {
2667 new_pos = max_frames - (*i)->length();
2669 new_pos = (*i)->position() + distance;
2674 if ((*i)->position() > distance) {
2675 new_pos = (*i)->position() - distance;
2681 (*i)->set_position (new_pos, this);
2689 notify_length_changed ();
2694 boost::shared_ptr<Region>
2695 Playlist::find_region (const ID& id) const
2697 RegionLock rlock (const_cast<Playlist*> (this));
2699 /* searches all regions currently in use by the playlist */
2701 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2702 if ((*i)->id() == id) {
2707 return boost::shared_ptr<Region> ();
2710 boost::shared_ptr<Region>
2711 Playlist::region_by_id (const ID& id) const
2713 /* searches all regions ever added to this playlist */
2715 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2716 if ((*i)->id() == id) {
2720 return boost::shared_ptr<Region> ();
2724 Playlist::dump () const
2726 boost::shared_ptr<Region> r;
2728 cerr << "Playlist \"" << _name << "\" " << endl
2729 << regions.size() << " regions "
2732 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2734 cerr << " " << r->name() << " ["
2735 << r->start() << "+" << r->length()
2745 Playlist::set_frozen (bool yn)
2751 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2753 region->set_last_layer_op (++layer_op_counter);
2758 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2762 if (region->locked()) {
2769 RegionLock rlock (const_cast<Playlist*> (this));
2774 RegionList::iterator next;
2776 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2777 if ((*i) == region) {
2781 if (next != regions.end()) {
2783 if ((*next)->locked()) {
2789 if ((*next)->position() != region->last_frame() + 1) {
2790 /* they didn't used to touch, so after shuffle,
2791 just have them swap positions.
2793 new_pos = (*next)->position();
2795 /* they used to touch, so after shuffle,
2796 make sure they still do. put the earlier
2797 region where the later one will end after
2800 new_pos = region->position() + (*next)->length();
2803 (*next)->set_position (region->position(), this);
2804 region->set_position (new_pos, this);
2806 /* avoid a full sort */
2808 regions.erase (i); // removes the region from the list */
2810 regions.insert (next, region); // adds it back after next
2819 RegionList::iterator prev = regions.end();
2821 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2822 if ((*i) == region) {
2824 if (prev != regions.end()) {
2826 if ((*prev)->locked()) {
2831 if (region->position() != (*prev)->last_frame() + 1) {
2832 /* they didn't used to touch, so after shuffle,
2833 just have them swap positions.
2835 new_pos = region->position();
2837 /* they used to touch, so after shuffle,
2838 make sure they still do. put the earlier
2839 one where the later one will end after
2841 new_pos = (*prev)->position() + region->length();
2844 region->set_position ((*prev)->position(), this);
2845 (*prev)->set_position (new_pos, this);
2847 /* avoid a full sort */
2849 regions.erase (i); // remove region
2850 regions.insert (prev, region); // insert region before prev
2866 check_dependents (region, false);
2868 notify_contents_changed();
2874 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2876 RegionLock rlock (const_cast<Playlist*> (this));
2878 if (regions.size() > 1) {
2886 Playlist::update_after_tempo_map_change ()
2888 RegionLock rlock (const_cast<Playlist*> (this));
2889 RegionList copy (regions.rlist());
2893 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2894 (*i)->update_position_after_tempo_map_change ();
2901 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2903 RegionLock rl (this, false);
2904 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2910 Playlist::set_explicit_relayering (bool e)
2912 if (e == false && _explicit_relayering == true) {
2914 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2915 we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2916 occurs. Hence now we'll set up region last_layer_op values so that an implicit relayer
2917 at this point would keep regions on the same layers.
2919 From then on in, it's just you and your towel.
2922 RegionLock rl (this);
2923 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2924 (*i)->set_last_layer_op ((*i)->layer ());
2928 _explicit_relayering = e;
2933 Playlist::has_region_at (framepos_t const p) const
2935 RegionLock (const_cast<Playlist *> (this));
2937 RegionList::const_iterator i = regions.begin ();
2938 while (i != regions.end() && !(*i)->covers (p)) {
2942 return (i != regions.end());
2945 /** Remove any region that uses a given source */
2947 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
2949 RegionLock rl (this);
2951 RegionList::iterator i = regions.begin();
2952 while (i != regions.end()) {
2953 RegionList::iterator j = i;
2956 if ((*i)->uses_source (s)) {
2957 remove_region_internal (*i);