2 * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2006-2016 David Robillard <d@drobilla.net>
4 * Copyright (C) 2006 Sampo Savolainen <v2@iki.fi>
5 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
7 * Copyright (C) 2014-2018 Colin Fletcher <colin.m.fletcher@googlemail.com>
8 * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
10 * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
11 * Copyright (C) 2016-2017 Tim Mayberry <mojofunk@gmail.com>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include "pbd/types_convert.h"
34 #include "pbd/stateful_diff_command.h"
35 #include "pbd/strsplit.h"
36 #include "pbd/unwind.h"
37 #include "pbd/xml++.h"
39 #include "ardour/debug.h"
40 #include "ardour/midi_region.h"
41 #include "ardour/playlist.h"
42 #include "ardour/playlist_factory.h"
43 #include "ardour/playlist_source.h"
44 #include "ardour/region.h"
45 #include "ardour/region_factory.h"
46 #include "ardour/region_sorters.h"
47 #include "ardour/session.h"
48 #include "ardour/session_playlists.h"
49 #include "ardour/source_factory.h"
50 #include "ardour/tempo.h"
51 #include "ardour/transient_detector.h"
52 #include "ardour/types_convert.h"
57 using namespace ARDOUR;
61 namespace Properties {
62 PBD::PropertyDescriptor<bool> regions;
66 struct ShowMeTheList {
67 ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
69 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
71 boost::shared_ptr<Playlist> playlist;
76 Playlist::make_property_quarks ()
78 Properties::regions.property_id = g_quark_from_static_string (X_("regions"));
79 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n",
80 Properties::regions.property_id));
83 RegionListProperty::RegionListProperty (Playlist& pl)
84 : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
90 RegionListProperty::RegionListProperty (RegionListProperty const & p)
91 : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
92 , _playlist (p._playlist)
98 RegionListProperty::clone () const
100 return new RegionListProperty (*this);
104 RegionListProperty::create () const
106 return new RegionListProperty (_playlist);
110 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
112 /* All regions (even those which are deleted) have their state
113 * saved by other code, so we can just store ID here.
116 node.set_property ("id", region->id());
119 boost::shared_ptr<Region>
120 RegionListProperty::get_content_from_xml (XMLNode const & node) const
123 if (!node.get_property ("id", id)) {
127 boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
130 ret = RegionFactory::region_by_id (id);
136 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
137 : SessionObject(sess, nom)
142 first_set_state = false;
147 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
148 : SessionObject(sess, "unnamed playlist")
153 XMLProperty const * prop = node.property("type");
154 assert(!prop || DataType(prop->value()) == _type);
158 _name = "unnamed"; /* reset by set_state */
161 /* set state called by derived class */
164 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
165 : SessionObject(other->_session, namestr)
167 , _type(other->_type)
168 , _orig_track_id (other->_orig_track_id)
169 , _shared_with_ids (other->_shared_with_ids)
174 other->copy_regions (tmp);
178 for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
179 add_region_internal( (*x), (*x)->position());
184 _splicing = other->_splicing;
185 _rippling = other->_rippling;
186 _nudging = other->_nudging;
187 _edit_mode = other->_edit_mode;
190 first_set_state = false;
192 in_partition = false;
194 _frozen = other->_frozen;
197 Playlist::Playlist (boost::shared_ptr<const Playlist> other, samplepos_t start, samplecnt_t cnt, string str, bool hide)
198 : SessionObject(other->_session, str)
200 , _type(other->_type)
201 , _orig_track_id (other->_orig_track_id)
202 , _shared_with_ids (other->_shared_with_ids)
204 RegionReadLock rlock2 (const_cast<Playlist*> (other.get()));
206 samplepos_t end = start + cnt - 1;
212 for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
214 boost::shared_ptr<Region> region;
215 boost::shared_ptr<Region> new_region;
216 sampleoffset_t offset = 0;
217 samplepos_t position = 0;
220 Evoral::OverlapType overlap;
224 overlap = region->coverage (start, end);
227 case Evoral::OverlapNone:
230 case Evoral::OverlapInternal:
231 offset = start - region->position();
236 case Evoral::OverlapStart:
238 position = region->position() - start;
239 len = end - region->position();
242 case Evoral::OverlapEnd:
243 offset = start - region->position();
245 len = region->length() - offset;
248 case Evoral::OverlapExternal:
250 position = region->position() - start;
251 len = region->length();
255 RegionFactory::region_name (new_name, region->name(), false);
259 plist.add (Properties::start, region->start() + offset);
260 plist.add (Properties::length, len);
261 plist.add (Properties::name, new_name);
262 plist.add (Properties::layer, region->layer());
263 plist.add (Properties::layering_index, region->layering_index());
265 new_region = RegionFactory::create (region, plist);
267 add_region_internal (new_region, position);
270 //keep track of any dead space at end (for pasting into Ripple or Splice mode)
271 //at the end of construction, any length of cnt beyond the extents of the regions is end_space
272 _end_space = cnt - (get_extent().second - get_extent().first);
275 first_set_state = false;
282 InUse (true); /* EMIT SIGNAL */
293 InUse (false); /* EMIT SIGNAL */
298 Playlist::copy_regions (RegionList& newlist) const
300 RegionReadLock rlock (const_cast<Playlist *> (this));
302 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
303 newlist.push_back (RegionFactory::create (*i, true, true));
308 Playlist::init (bool hide)
310 add_property (regions);
311 _xml_node_name = X_("Playlist");
313 g_atomic_int_set (&block_notifications, 0);
314 g_atomic_int_set (&ignore_state_changes, 0);
315 pending_contents_change = false;
316 pending_layering = false;
317 first_set_state = true;
326 _edit_mode = Config->get_edit_mode();
328 in_partition = false;
331 _capture_insertion_underway = false;
334 _playlist_shift_active = false;
336 _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
337 _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
339 ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
342 Playlist::~Playlist ()
344 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
347 RegionReadLock rl (this);
349 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
350 (*i)->set_playlist (boost::shared_ptr<Playlist>());
354 /* GoingAway must be emitted by derived classes */
358 Playlist::_set_sort_id ()
360 /* Playlists are given names like <track name>.<id>
361 * or <track name>.<edit group name>.<id> where id
362 * is an integer. We extract the id and sort by that.
365 size_t dot_position = _name.val().find_last_of(".");
367 if (dot_position == string::npos) {
370 string t = _name.val().substr(dot_position + 1);
372 if (!string_to_uint32 (t, _sort_id)) {
379 Playlist::set_name (const string& str)
381 /* in a typical situation, a playlist is being used
382 * by one diskstream and also is referenced by the
383 * Session. if there are more references than that,
384 * then don't change the name.
391 bool ret = SessionObject::set_name(str);
398 /***********************************************************************
399 * CHANGE NOTIFICATION HANDLING
401 * Notifications must be delayed till the region_lock is released. This
402 * is necessary because handlers for the signals may need to acquire
403 * the lock (e.g. to read from the playlist).
404 ***********************************************************************/
407 Playlist::begin_undo ()
414 Playlist::end_undo ()
423 delay_notifications ();
424 g_atomic_int_inc (&ignore_state_changes);
427 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
429 Playlist::thaw (bool from_undo)
431 g_atomic_int_dec_and_test (&ignore_state_changes);
432 release_notifications (from_undo);
437 Playlist::delay_notifications ()
439 g_atomic_int_inc (&block_notifications);
442 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
444 Playlist::release_notifications (bool from_undo)
446 if (g_atomic_int_dec_and_test (&block_notifications)) {
447 flush_notifications (from_undo);
452 Playlist::notify_contents_changed ()
454 if (holding_state ()) {
455 pending_contents_change = true;
457 pending_contents_change = false;
458 ContentsChanged(); /* EMIT SIGNAL */
463 Playlist::notify_layering_changed ()
465 if (holding_state ()) {
466 pending_layering = true;
468 pending_layering = false;
469 LayeringChanged(); /* EMIT SIGNAL */
474 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
476 if (holding_state ()) {
477 pending_removes.insert (r);
478 pending_contents_change = true;
480 /* this might not be true, but we have to act
481 as though it could be.
483 pending_contents_change = false;
484 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
485 ContentsChanged (); /* EMIT SIGNAL */
490 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
492 Evoral::RangeMove<samplepos_t> const move (r->last_position (), r->length (), r->position ());
494 if (holding_state ()) {
496 pending_range_moves.push_back (move);
500 list< Evoral::RangeMove<samplepos_t> > m;
502 RangesMoved (m, false);
508 Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r)
510 if (r->position() >= r->last_position()) {
511 /* trimmed shorter */
515 Evoral::Range<samplepos_t> const extra (r->position(), r->last_position());
517 if (holding_state ()) {
519 pending_region_extensions.push_back (extra);
523 list<Evoral::Range<samplepos_t> > r;
531 Playlist::notify_region_end_trimmed (boost::shared_ptr<Region> r)
533 if (r->length() < r->last_length()) {
534 /* trimmed shorter */
537 Evoral::Range<samplepos_t> const extra (r->position() + r->last_length(), r->position() + r->length());
539 if (holding_state ()) {
541 pending_region_extensions.push_back (extra);
545 list<Evoral::Range<samplepos_t> > r;
553 Playlist::notify_region_added (boost::shared_ptr<Region> r)
555 /* the length change might not be true, but we have to act
556 * as though it could be.
559 if (holding_state()) {
560 pending_adds.insert (r);
561 pending_contents_change = true;
564 pending_contents_change = false;
565 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
566 ContentsChanged (); /* EMIT SIGNAL */
571 /** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
573 Playlist::flush_notifications (bool from_undo)
575 set<boost::shared_ptr<Region> >::iterator s;
576 bool regions_changed = false;
584 if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
585 regions_changed = true;
588 /* XXX: it'd be nice if we could use pending_bounds for
589 RegionsExtended and RegionsMoved.
592 /* we have no idea what order the regions ended up in pending
593 * bounds (it could be based on selection order, for example).
594 * so, to preserve layering in the "most recently moved is higher"
595 * model, sort them by existing layer, then timestamp them.
598 // RegionSortByLayer cmp;
599 // pending_bounds.sort (cmp);
601 list<Evoral::Range<samplepos_t> > crossfade_ranges;
603 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
604 crossfade_ranges.push_back ((*r)->last_range ());
605 crossfade_ranges.push_back ((*r)->range ());
608 for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
609 crossfade_ranges.push_back ((*s)->range ());
610 remove_dependents (*s);
611 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
612 Region::RegionPropertyChanged(*s, Properties::hidden);
615 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
616 crossfade_ranges.push_back ((*s)->range ());
617 /* don't emit RegionAdded signal until relayering is done,
618 so that the region is fully setup by the time
619 anyone hears that its been added
623 /* notify about contents/region changes first so that layering changes
624 * in a UI will take place on the new contents.
627 if (regions_changed || pending_contents_change) {
628 pending_layering = true;
629 ContentsChanged (); /* EMIT SIGNAL */
632 for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
633 (*s)->clear_changes ();
634 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
637 if ((regions_changed && !in_set_state) || pending_layering) {
641 coalesce_and_check_crossfades (crossfade_ranges);
643 if (!pending_range_moves.empty ()) {
644 /* We don't need to check crossfades for these as pending_bounds has
647 RangesMoved (pending_range_moves, from_undo || _playlist_shift_active);
650 if (!pending_region_extensions.empty ()) {
651 RegionsExtended (pending_region_extensions);
660 Playlist::clear_pending ()
662 pending_adds.clear ();
663 pending_removes.clear ();
664 pending_bounds.clear ();
665 pending_range_moves.clear ();
666 pending_region_extensions.clear ();
667 pending_contents_change = false;
668 pending_layering = false;
671 /*************************************************************
672 * PLAYLIST OPERATIONS
673 *************************************************************/
675 /** Note: this calls set_layer (..., DBL_MAX) so it will reset the layering index of region */
677 Playlist::add_region (boost::shared_ptr<Region> region, samplepos_t position, float times, bool auto_partition, int32_t sub_num, double quarter_note, bool for_music)
679 RegionWriteLock rlock (this);
680 times = fabs (times);
682 int itimes = (int) floor (times);
684 samplepos_t pos = position;
686 if (times == 1 && auto_partition){
688 partition_internal (pos - 1, (pos + region->length()), true, thawlist);
689 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
690 (*i)->resume_property_changes ();
691 _session.add_command (new StatefulDiffCommand (*i));
696 add_region_internal (region, pos, sub_num, quarter_note, for_music);
697 set_layer (region, DBL_MAX);
698 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, true);
708 add_region_internal (copy, pos, sub_num);
709 set_layer (copy, DBL_MAX);
710 pos += region->length();
713 samplecnt_t length = 0;
715 if (floor (times) != times) {
716 length = (samplecnt_t) floor (region->length() * (times - floor (times)));
718 RegionFactory::region_name (name, region->name(), false);
723 plist.add (Properties::start, region->start());
724 plist.add (Properties::length, length);
725 plist.add (Properties::name, name);
726 plist.add (Properties::layer, region->layer());
728 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
729 add_region_internal (sub, pos, sub_num);
730 set_layer (sub, DBL_MAX);
734 possibly_splice_unlocked (position, (pos + length) - position, region);
738 Playlist::set_region_ownership ()
740 RegionWriteLock rl (this);
741 RegionList::iterator i;
742 boost::weak_ptr<Playlist> pl (shared_from_this());
744 for (i = regions.begin(); i != regions.end(); ++i) {
745 (*i)->set_playlist (pl);
750 Playlist::add_region_internal (boost::shared_ptr<Region> region, samplepos_t position, int32_t sub_num, double quarter_note, bool for_music)
752 if (region->data_type() != _type) {
756 RegionSortByPosition cmp;
758 if (!first_set_state) {
759 boost::shared_ptr<Playlist> foo (shared_from_this());
760 region->set_playlist (boost::weak_ptr<Playlist>(foo));
763 region->set_position_music (quarter_note);
765 region->set_position (position, sub_num);
768 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
769 all_regions.insert (region);
771 possibly_splice_unlocked (position, region->length(), region);
773 if (!holding_state ()) {
774 /* layers get assigned from XML state, and are not reset during undo/redo */
778 /* we need to notify the existence of new region before checking dependents. Ick. */
780 notify_region_added (region);
782 region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
783 region->DropReferences.connect_same_thread (region_drop_references_connections, boost::bind (&Playlist::region_going_away, this, boost::weak_ptr<Region> (region)));
789 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, samplepos_t pos)
791 RegionWriteLock rlock (this);
793 bool old_sp = _splicing;
796 remove_region_internal (old);
797 add_region_internal (newr, pos);
798 set_layer (newr, old->layer ());
802 possibly_splice_unlocked (pos, old->length() - newr->length());
806 Playlist::remove_region (boost::shared_ptr<Region> region)
808 RegionWriteLock rlock (this);
809 remove_region_internal (region);
813 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
815 RegionList::iterator i;
819 region->set_playlist (boost::weak_ptr<Playlist>());
822 /* XXX should probably freeze here .... */
824 for (i = regions.begin(); i != regions.end(); ++i) {
827 samplepos_t pos = (*i)->position();
828 samplecnt_t distance = (*i)->length();
832 possibly_splice_unlocked (pos, -distance);
834 if (!holding_state ()) {
836 remove_dependents (region);
839 notify_region_removed (region);
848 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
850 switch (Config->get_region_equivalence()) {
852 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
853 if ((*i)->exact_equivalent (other)) {
854 results.push_back (*i);
859 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
860 if ((*i)->layer_and_time_equivalent (other)) {
861 results.push_back (*i);
866 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
867 if ((*i)->enclosed_equivalent (other)) {
868 results.push_back (*i);
873 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
874 if ((*i)->overlap_equivalent (other)) {
875 results.push_back (*i);
883 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
885 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
887 if ((*i) && (*i)->region_list_equivalent (other)) {
888 results.push_back (*i);
894 Playlist::get_source_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
896 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
898 if ((*i) && (*i)->any_source_equivalent (other)) {
899 results.push_back (*i);
905 Playlist::partition (samplepos_t start, samplepos_t end, bool cut)
909 RegionWriteLock lock(this);
910 partition_internal (start, end, cut, thawlist);
913 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
914 (*i)->resume_property_changes ();
918 /* If a MIDI region is locked to musical-time, Properties::start is ignored
919 * and _start is overwritten using Properties::start_beats in
920 * add_region_internal() -> Region::set_position() -> MidiRegion::set_position_internal()
922 static void maybe_add_start_beats (TempoMap const& tm, PropertyList& plist, boost::shared_ptr<Region> r, samplepos_t start, samplepos_t end)
924 boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(r);
928 double delta_beats = tm.quarter_notes_between_samples (start, end);
929 plist.add (Properties::start_beats, mr->start_beats () + delta_beats);
932 /** Go through each region on the playlist and cut them at start and end, removing the section between
933 * start and end if cutting == true. Regions that lie entirely within start and end are always
937 Playlist::partition_internal (samplepos_t start, samplepos_t end, bool cutting, RegionList& thawlist)
939 RegionList new_regions;
943 boost::shared_ptr<Region> region;
944 boost::shared_ptr<Region> current;
946 RegionList::iterator tmp;
947 Evoral::OverlapType overlap;
948 samplepos_t pos1, pos2, pos3, pos4;
952 /* need to work from a copy, because otherwise the regions we add
953 * during the process get operated on as well.
956 RegionList copy = regions.rlist();
958 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
965 if (current->first_sample() >= start && current->last_sample() < end) {
968 remove_region_internal (current);
974 /* coverage will return OverlapStart if the start coincides
975 * with the end point. we do not partition such a region,
976 * so catch this special case.
979 if (current->first_sample() >= end) {
983 if ((overlap = current->coverage (start, end)) == Evoral::OverlapNone) {
987 pos1 = current->position();
990 pos4 = current->last_sample();
992 if (overlap == Evoral::OverlapInternal) {
993 /* split: we need 3 new regions, the front, middle and end.
994 * cut: we need 2 regions, the front and end.
998 * ---------------*************************------------
1001 * ---------------*****++++++++++++++++====------------
1003 * ---------------*****----------------====------------
1007 /* "middle" ++++++ */
1009 RegionFactory::region_name (new_name, current->name(), false);
1013 plist.add (Properties::start, current->start() + (pos2 - pos1));
1014 plist.add (Properties::length, pos3 - pos2);
1015 plist.add (Properties::name, new_name);
1016 plist.add (Properties::layer, current->layer ());
1017 plist.add (Properties::layering_index, current->layering_index ());
1018 plist.add (Properties::automatic, true);
1019 plist.add (Properties::left_of_split, true);
1020 plist.add (Properties::right_of_split, true);
1021 maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start() + (pos2 - pos1));
1023 /* see note in :_split_region()
1024 * for MusicSample is needed to offset region-gain
1026 region = RegionFactory::create (current, MusicSample (pos2 - pos1, 0), plist);
1027 add_region_internal (region, start);
1028 new_regions.push_back (region);
1033 RegionFactory::region_name (new_name, current->name(), false);
1037 plist.add (Properties::start, current->start() + (pos3 - pos1));
1038 plist.add (Properties::length, pos4 - pos3);
1039 plist.add (Properties::name, new_name);
1040 plist.add (Properties::layer, current->layer ());
1041 plist.add (Properties::layering_index, current->layering_index ());
1042 plist.add (Properties::automatic, true);
1043 plist.add (Properties::right_of_split, true);
1044 maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start() + (pos3 - pos1));
1046 region = RegionFactory::create (current, MusicSample (pos3 - pos1, 0), plist);
1048 add_region_internal (region, end);
1049 new_regions.push_back (region);
1053 current->clear_changes ();
1054 current->suspend_property_changes ();
1055 thawlist.push_back (current);
1056 current->cut_end (pos2 - 1);
1058 } else if (overlap == Evoral::OverlapEnd) {
1062 ---------------*************************------------
1065 ---------------**************+++++++++++------------
1067 ---------------**************-----------------------
1074 RegionFactory::region_name (new_name, current->name(), false);
1078 plist.add (Properties::start, current->start() + (pos2 - pos1));
1079 plist.add (Properties::length, pos4 - pos2);
1080 plist.add (Properties::name, new_name);
1081 plist.add (Properties::layer, current->layer ());
1082 plist.add (Properties::layering_index, current->layering_index ());
1083 plist.add (Properties::automatic, true);
1084 plist.add (Properties::left_of_split, true);
1085 maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start() + (pos2 - pos1));
1087 region = RegionFactory::create (current, MusicSample(pos2 - pos1, 0), plist);
1089 add_region_internal (region, start);
1090 new_regions.push_back (region);
1095 current->clear_changes ();
1096 current->suspend_property_changes ();
1097 thawlist.push_back (current);
1098 current->cut_end (pos2 - 1);
1100 } else if (overlap == Evoral::OverlapStart) {
1102 /* split: we need 2 regions: the front and the end.
1103 * cut: just trim current to skip the cut area
1107 * ---------------*************************------------
1111 * ---------------****+++++++++++++++++++++------------
1113 * -------------------*********************------------
1118 RegionFactory::region_name (new_name, current->name(), false);
1122 plist.add (Properties::start, current->start());
1123 plist.add (Properties::length, pos3 - pos1);
1124 plist.add (Properties::name, new_name);
1125 plist.add (Properties::layer, current->layer ());
1126 plist.add (Properties::layering_index, current->layering_index ());
1127 plist.add (Properties::automatic, true);
1128 plist.add (Properties::right_of_split, true);
1129 maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start());
1131 region = RegionFactory::create (current, plist);
1133 add_region_internal (region, pos1);
1134 new_regions.push_back (region);
1139 current->clear_changes ();
1140 current->suspend_property_changes ();
1141 thawlist.push_back (current);
1142 current->trim_front (pos3);
1143 } else if (overlap == Evoral::OverlapExternal) {
1145 /* split: no split required.
1146 * cut: remove the region.
1150 * ---------------*************************------------
1155 * ---------------*************************------------
1157 * ----------------------------------------------------
1162 remove_region_internal (current);
1165 new_regions.push_back (current);
1169 in_partition = false;
1172 //keep track of any dead space at end (for pasting into Ripple or Splice mode)
1173 samplepos_t wanted_length = end-start;
1174 _end_space = wanted_length - _get_extent().second - _get_extent().first;
1177 boost::shared_ptr<Playlist>
1178 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t, samplecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1180 boost::shared_ptr<Playlist> ret;
1181 boost::shared_ptr<Playlist> pl;
1184 if (ranges.empty()) {
1185 return boost::shared_ptr<Playlist>();
1188 start = ranges.front().start;
1190 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1192 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1194 if (i == ranges.begin()) {
1198 /* paste the next section into the nascent playlist,
1199 * offset to reflect the start of the first range we
1203 ret->paste (pl, (*i).start - start, 1.0f, 0);
1210 boost::shared_ptr<Playlist>
1211 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1213 boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t,samplecnt_t,bool) = &Playlist::cut;
1214 return cut_copy (pmf, ranges, result_is_hidden);
1217 boost::shared_ptr<Playlist>
1218 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1220 boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t,samplecnt_t,bool) = &Playlist::copy;
1221 return cut_copy (pmf, ranges, result_is_hidden);
1224 boost::shared_ptr<Playlist>
1225 Playlist::cut (samplepos_t start, samplecnt_t cnt, bool result_is_hidden)
1227 boost::shared_ptr<Playlist> the_copy;
1228 RegionList thawlist;
1231 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1232 string new_name = _name;
1236 if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1237 return boost::shared_ptr<Playlist>();
1241 RegionWriteLock rlock (this);
1242 partition_internal (start, start+cnt-1, true, thawlist);
1245 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1246 (*i)->resume_property_changes();
1252 boost::shared_ptr<Playlist>
1253 Playlist::copy (samplepos_t start, samplecnt_t cnt, bool result_is_hidden)
1257 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1258 string new_name = _name;
1262 // cnt = min (_get_extent().second - start, cnt); (We need the full range length when copy/pasting in Ripple. Why was this limit here? It's not in CUT... )
1264 return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1268 Playlist::paste (boost::shared_ptr<Playlist> other, samplepos_t position, float times, const int32_t sub_num)
1270 times = fabs (times);
1273 RegionReadLock rl2 (other.get());
1275 int itimes = (int) floor (times);
1276 samplepos_t pos = position;
1277 samplecnt_t const shift = other->_get_extent().second;
1278 layer_t top = top_layer ();
1281 RegionWriteLock rl1 (this);
1283 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1284 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1286 /* put these new regions on top of all existing ones, but preserve
1287 the ordering they had in the original playlist.
1290 add_region_internal (copy_of_region, (*i)->position() + pos, sub_num);
1291 set_layer (copy_of_region, copy_of_region->layer() + top);
1303 Playlist::duplicate (boost::shared_ptr<Region> region, samplepos_t position, float times)
1305 duplicate(region, position, region->length(), times);
1308 /** @param gap from the beginning of the region to the next beginning */
1310 Playlist::duplicate (boost::shared_ptr<Region> region, samplepos_t position, samplecnt_t gap, float times)
1312 times = fabs (times);
1314 RegionWriteLock rl (this);
1315 int itimes = (int) floor (times);
1318 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1319 add_region_internal (copy, position);
1320 set_layer (copy, DBL_MAX);
1324 if (floor (times) != times) {
1325 samplecnt_t length = (samplecnt_t) floor (region->length() * (times - floor (times)));
1327 RegionFactory::region_name (name, region->name(), false);
1332 plist.add (Properties::start, region->start());
1333 plist.add (Properties::length, length);
1334 plist.add (Properties::name, name);
1336 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1337 add_region_internal (sub, position);
1338 set_layer (sub, DBL_MAX);
1343 /** @param gap from the beginning of the region to the next beginning */
1344 /** @param end the first sample that does _not_ contain a duplicated sample */
1346 Playlist::duplicate_until (boost::shared_ptr<Region> region, samplepos_t position, samplecnt_t gap, samplepos_t end)
1348 RegionWriteLock rl (this);
1350 while (position + region->length() - 1 < end) {
1351 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1352 add_region_internal (copy, position);
1353 set_layer (copy, DBL_MAX);
1357 if (position < end) {
1358 samplecnt_t length = min (region->length(), end - position);
1360 RegionFactory::region_name (name, region->name(), false);
1365 plist.add (Properties::start, region->start());
1366 plist.add (Properties::length, length);
1367 plist.add (Properties::name, name);
1369 boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1370 add_region_internal (sub, position);
1371 set_layer (sub, DBL_MAX);
1377 Playlist::duplicate_range (AudioRange& range, float times)
1379 boost::shared_ptr<Playlist> pl = copy (range.start, range.length(), true);
1380 samplecnt_t offset = range.end - range.start;
1381 paste (pl, range.start + offset, times, 0);
1385 Playlist::duplicate_ranges (std::list<AudioRange>& ranges, float times)
1387 if (ranges.empty()) {
1391 samplepos_t min_pos = max_samplepos;
1392 samplepos_t max_pos = 0;
1394 for (std::list<AudioRange>::const_iterator i = ranges.begin();
1397 min_pos = min (min_pos, (*i).start);
1398 max_pos = max (max_pos, (*i).end);
1401 samplecnt_t offset = max_pos - min_pos;
1404 int itimes = (int) floor (times);
1406 for (list<AudioRange>::iterator i = ranges.begin (); i != ranges.end (); ++i) {
1407 boost::shared_ptr<Playlist> pl = copy ((*i).start, (*i).length (), true);
1408 paste (pl, (*i).start + (offset * count), 1.0f, 0);
1415 Playlist::shift (samplepos_t at, sampleoffset_t distance, bool move_intersected, bool ignore_music_glue)
1417 PBD::Unwinder<bool> uw (_playlist_shift_active, true);
1418 RegionWriteLock rlock (this);
1419 RegionList copy (regions.rlist());
1422 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1424 if ((*r)->last_sample() < at) {
1429 if (at > (*r)->first_sample() && at < (*r)->last_sample()) {
1430 /* intersected region */
1431 if (!move_intersected) {
1436 /* do not move regions glued to music time - that
1437 * has to be done separately.
1440 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1441 fixup.push_back (*r);
1445 (*r)->set_position ((*r)->position() + distance);
1448 /* XXX: may not be necessary; Region::post_set should do this, I think */
1449 for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1450 (*r)->recompute_position_from_lock_style (0);
1455 Playlist::split (const MusicSample& at)
1457 RegionWriteLock rlock (this);
1458 RegionList copy (regions.rlist());
1460 /* use a copy since this operation can modify the region list */
1462 for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1463 _split_region (*r, at);
1468 Playlist::split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position)
1470 RegionWriteLock rl (this);
1471 _split_region (region, playlist_position);
1475 Playlist::_split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position)
1477 if (!region->covers (playlist_position.sample)) {
1481 if (region->position() == playlist_position.sample ||
1482 region->last_sample() == playlist_position.sample) {
1486 boost::shared_ptr<Region> left;
1487 boost::shared_ptr<Region> right;
1489 MusicSample before (playlist_position.sample - region->position(), playlist_position.division);
1490 MusicSample after (region->length() - before.sample, 0);
1494 /* split doesn't change anything about length, so don't try to splice */
1496 bool old_sp = _splicing;
1499 RegionFactory::region_name (before_name, region->name(), false);
1504 plist.add (Properties::length, before.sample);
1505 plist.add (Properties::name, before_name);
1506 plist.add (Properties::left_of_split, true);
1507 plist.add (Properties::layering_index, region->layering_index ());
1508 plist.add (Properties::layer, region->layer ());
1510 /* note: we must use the version of ::create with an offset here,
1511 * since it supplies that offset to the Region constructor, which
1512 * is necessary to get audio region gain envelopes right.
1514 left = RegionFactory::create (region, MusicSample (0, 0), plist, true);
1517 RegionFactory::region_name (after_name, region->name(), false);
1522 plist.add (Properties::length, after.sample);
1523 plist.add (Properties::name, after_name);
1524 plist.add (Properties::right_of_split, true);
1525 plist.add (Properties::layering_index, region->layering_index ());
1526 plist.add (Properties::layer, region->layer ());
1528 /* same note as above */
1529 right = RegionFactory::create (region, before, plist, true);
1532 add_region_internal (left, region->position(), 0);
1533 add_region_internal (right, region->position() + before.sample, before.division);
1535 remove_region_internal (region);
1541 Playlist::AddToSoloSelectedList(const Region* r)
1543 _soloSelectedRegions.insert (r);
1548 Playlist::RemoveFromSoloSelectedList(const Region* r)
1550 _soloSelectedRegions.erase (r);
1555 Playlist::SoloSelectedListIncludes(const Region* r)
1557 std::set<const Region*>::iterator i = _soloSelectedRegions.find(r);
1559 return ( i != _soloSelectedRegions.end() );
1563 Playlist::SoloSelectedActive()
1565 return !_soloSelectedRegions.empty();
1570 Playlist::possibly_splice (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1572 if (_splicing || in_set_state) {
1573 /* don't respond to splicing moves or state setting */
1577 if (_edit_mode == Splice) {
1578 splice_locked (at, distance, exclude);
1583 Playlist::possibly_splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1585 if (_splicing || in_set_state) {
1586 /* don't respond to splicing moves or state setting */
1590 if (_edit_mode == Splice) {
1591 splice_unlocked (at, distance, exclude);
1596 Playlist::splice_locked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1599 RegionWriteLock rl (this);
1600 core_splice (at, distance, exclude);
1605 Playlist::splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1607 core_splice (at, distance, exclude);
1611 Playlist::core_splice (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1615 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1617 if (exclude && (*i) == exclude) {
1621 if ((*i)->position() >= at) {
1622 samplepos_t new_pos = (*i)->position() + distance;
1625 } else if (new_pos >= max_samplepos - (*i)->length()) {
1626 new_pos = max_samplepos - (*i)->length();
1629 (*i)->set_position (new_pos);
1635 notify_contents_changed ();
1639 Playlist::ripple_locked (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1642 RegionWriteLock rl (this);
1643 core_ripple (at, distance, exclude);
1648 Playlist::ripple_unlocked (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1650 core_ripple (at, distance, exclude);
1654 Playlist::core_ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1656 if (distance == 0) {
1661 RegionListProperty copy = regions;
1662 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1663 assert (i != copy.end());
1666 if (std::find(exclude->begin(), exclude->end(), (*i)) != exclude->end()) {
1671 if ((*i)->position() >= at) {
1672 samplepos_t new_pos = (*i)->position() + distance;
1673 samplepos_t limit = max_samplepos - (*i)->length();
1676 } else if (new_pos >= limit ) {
1680 (*i)->set_position (new_pos);
1685 notify_contents_changed ();
1690 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1692 if (in_set_state || _splicing || _rippling || _nudging || _shuffling) {
1696 if (what_changed.contains (Properties::position)) {
1698 /* remove it from the list then add it back in
1699 * the right place again.
1702 RegionSortByPosition cmp;
1704 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1706 if (i == regions.end()) {
1707 /* the region bounds are being modified but its not currently
1708 * in the region list. we will use its bounds correctly when/if
1715 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1718 if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1720 sampleoffset_t delta = 0;
1722 if (what_changed.contains (Properties::position)) {
1723 delta = region->position() - region->last_position();
1726 if (what_changed.contains (Properties::length)) {
1727 delta += region->length() - region->last_length();
1731 possibly_splice (region->last_position() + region->last_length(), delta, region);
1734 if (holding_state ()) {
1735 pending_bounds.push_back (region);
1737 notify_contents_changed ();
1739 list<Evoral::Range<samplepos_t> > xf;
1740 xf.push_back (Evoral::Range<samplepos_t> (region->last_range()));
1741 xf.push_back (Evoral::Range<samplepos_t> (region->range()));
1742 coalesce_and_check_crossfades (xf);
1748 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1750 boost::shared_ptr<Region> region (weak_region.lock());
1756 /* this makes a virtual call to the right kind of playlist ... */
1758 region_changed (what_changed, region);
1762 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1764 PropertyChange our_interests;
1765 PropertyChange bounds;
1768 if (in_set_state || in_flush) {
1772 our_interests.add (Properties::muted);
1773 our_interests.add (Properties::layer);
1774 our_interests.add (Properties::opaque);
1775 our_interests.add (Properties::contents);
1777 bounds.add (Properties::start);
1778 bounds.add (Properties::position);
1779 bounds.add (Properties::length);
1781 bool send_contents = false;
1783 if (what_changed.contains (bounds)) {
1784 region_bounds_changed (what_changed, region);
1785 save = !(_splicing || _nudging);
1786 send_contents = true;
1789 if (what_changed.contains (Properties::contents)) {
1790 send_contents = true;
1793 if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1794 notify_region_moved (region);
1795 } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1796 notify_region_end_trimmed (region);
1797 } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1798 notify_region_start_trimmed (region);
1801 /* don't notify about layer changes, since we are the only object that can initiate
1802 * them, and we notify in ::relayer()
1805 if (what_changed.contains (our_interests)) {
1809 if (send_contents || save) {
1810 notify_contents_changed ();
1813 mark_session_dirty ();
1819 Playlist::drop_regions ()
1821 RegionWriteLock rl (this);
1823 all_regions.clear ();
1827 Playlist::sync_all_regions_with_regions ()
1829 RegionWriteLock rl (this);
1831 all_regions.clear ();
1833 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1834 all_regions.insert (*i);
1839 Playlist::clear (bool with_signals)
1842 RegionWriteLock rl (this);
1844 region_state_changed_connections.drop_connections ();
1845 region_drop_references_connections.drop_connections ();
1847 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1848 pending_removes.insert (*i);
1853 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1854 remove_dependents (*s);
1860 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1861 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1864 pending_removes.clear ();
1865 pending_contents_change = false;
1871 /* *********************************************************************
1873 **********************************************************************/
1875 boost::shared_ptr<RegionList>
1876 Playlist::region_list()
1878 RegionReadLock rlock (this);
1879 boost::shared_ptr<RegionList> rlist (new RegionList (regions.rlist ()));
1884 Playlist::deep_sources (std::set<boost::shared_ptr<Source> >& sources) const
1886 RegionReadLock rlock (const_cast<Playlist*>(this));
1888 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1889 (*i)->deep_sources (sources);
1893 boost::shared_ptr<RegionList>
1894 Playlist::regions_at (samplepos_t sample)
1896 RegionReadLock rlock (this);
1897 return find_regions_at (sample);
1901 Playlist::count_regions_at (samplepos_t sample) const
1903 RegionReadLock rlock (const_cast<Playlist*>(this));
1906 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1907 if ((*i)->covers (sample)) {
1915 boost::shared_ptr<Region>
1916 Playlist::top_region_at (samplepos_t sample)
1918 RegionReadLock rlock (this);
1919 boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1920 boost::shared_ptr<Region> region;
1922 if (rlist->size()) {
1923 RegionSortByLayer cmp;
1925 region = rlist->back();
1931 boost::shared_ptr<Region>
1932 Playlist::top_unmuted_region_at (samplepos_t sample)
1934 RegionReadLock rlock (this);
1935 boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1937 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1939 RegionList::iterator tmp = i;
1943 if ((*i)->muted()) {
1950 boost::shared_ptr<Region> region;
1952 if (rlist->size()) {
1953 RegionSortByLayer cmp;
1955 region = rlist->back();
1961 boost::shared_ptr<RegionList>
1962 Playlist::find_regions_at (samplepos_t sample)
1964 /* Caller must hold lock */
1966 boost::shared_ptr<RegionList> rlist (new RegionList);
1968 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1969 if ((*i)->covers (sample)) {
1970 rlist->push_back (*i);
1977 boost::shared_ptr<RegionList>
1978 Playlist::regions_with_start_within (Evoral::Range<samplepos_t> range)
1980 RegionReadLock rlock (this);
1981 boost::shared_ptr<RegionList> rlist (new RegionList);
1983 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1984 if ((*i)->first_sample() >= range.from && (*i)->first_sample() <= range.to) {
1985 rlist->push_back (*i);
1992 boost::shared_ptr<RegionList>
1993 Playlist::regions_with_end_within (Evoral::Range<samplepos_t> range)
1995 RegionReadLock rlock (this);
1996 boost::shared_ptr<RegionList> rlist (new RegionList);
1998 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1999 if ((*i)->last_sample() >= range.from && (*i)->last_sample() <= range.to) {
2000 rlist->push_back (*i);
2007 boost::shared_ptr<RegionList>
2008 Playlist::regions_touched (samplepos_t start, samplepos_t end)
2010 RegionReadLock rlock (this);
2011 return regions_touched_locked (start, end);
2014 boost::shared_ptr<RegionList>
2015 Playlist::regions_touched_locked (samplepos_t start, samplepos_t end)
2017 boost::shared_ptr<RegionList> rlist (new RegionList);
2019 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2020 if ((*i)->coverage (start, end) != Evoral::OverlapNone) {
2021 rlist->push_back (*i);
2029 Playlist::find_next_transient (samplepos_t from, int dir)
2031 RegionReadLock rlock (this);
2032 AnalysisFeatureList points;
2033 AnalysisFeatureList these_points;
2035 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2037 if ((*i)->last_sample() < from) {
2041 if ((*i)->first_sample() > from) {
2046 (*i)->get_transients (these_points);
2048 /* add first sample, just, err, because */
2050 these_points.push_back ((*i)->first_sample());
2052 points.insert (points.end(), these_points.begin(), these_points.end());
2053 these_points.clear ();
2056 if (points.empty()) {
2060 TransientDetector::cleanup_transients (points, _session.sample_rate(), 3.0);
2061 bool reached = false;
2064 for (AnalysisFeatureList::const_iterator x = points.begin(); x != points.end(); ++x) {
2069 if (reached && (*x) > from) {
2074 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2079 if (reached && (*x) < from) {
2088 boost::shared_ptr<Region>
2089 Playlist::find_next_region (samplepos_t sample, RegionPoint point, int dir)
2091 RegionReadLock rlock (this);
2092 boost::shared_ptr<Region> ret;
2093 samplepos_t closest = max_samplepos;
2095 bool end_iter = false;
2097 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2101 sampleoffset_t distance;
2102 boost::shared_ptr<Region> r = (*i);
2103 samplepos_t pos = 0;
2107 pos = r->first_sample ();
2110 pos = r->last_sample ();
2113 pos = r->sync_position ();
2118 case 1: /* forwards */
2121 if ((distance = pos - sample) < closest) {
2130 default: /* backwards */
2133 if ((distance = sample - pos) < closest) {
2149 Playlist::find_next_region_boundary (samplepos_t sample, int dir)
2151 RegionReadLock rlock (this);
2153 samplepos_t closest = max_samplepos;
2154 samplepos_t ret = -1;
2158 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2160 boost::shared_ptr<Region> r = (*i);
2161 sampleoffset_t distance;
2162 const samplepos_t first_sample = r->first_sample();
2163 const samplepos_t last_sample = r->last_sample();
2165 if (first_sample > sample) {
2167 distance = first_sample - sample;
2169 if (distance < closest) {
2175 if (last_sample > sample) {
2177 distance = last_sample - sample;
2179 if (distance < closest) {
2188 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2190 boost::shared_ptr<Region> r = (*i);
2191 sampleoffset_t distance;
2192 const samplepos_t first_sample = r->first_sample();
2193 const samplepos_t last_sample = r->last_sample();
2195 if (last_sample < sample) {
2197 distance = sample - last_sample;
2199 if (distance < closest) {
2205 if (first_sample < sample) {
2207 distance = sample - first_sample;
2209 if (distance < closest) {
2220 /***********************************************************************/
2223 Playlist::mark_session_dirty ()
2225 if (!in_set_state && !holding_state ()) {
2226 _session.set_dirty();
2231 Playlist::rdiff (vector<Command*>& cmds) const
2233 RegionReadLock rlock (const_cast<Playlist *> (this));
2234 Stateful::rdiff (cmds);
2238 Playlist::clear_owned_changes ()
2240 RegionReadLock rlock (this);
2241 Stateful::clear_owned_changes ();
2245 Playlist::update (const RegionListProperty::ChangeRecord& change)
2247 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2248 name(), change.added.size(), change.removed.size()));
2251 /* add the added regions */
2252 for (RegionListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
2253 add_region_internal ((*i), (*i)->position());
2255 /* remove the removed regions */
2256 for (RegionListProperty::ChangeContainer::const_iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2264 Playlist::set_state (const XMLNode& node, int version)
2268 XMLNodeConstIterator niter;
2269 XMLPropertyConstIterator piter;
2270 boost::shared_ptr<Region> region;
2272 bool seen_region_nodes = false;
2277 if (node.name() != "Playlist") {
2287 if (node.get_property (X_("name"), name)) {
2292 /* XXX legacy session: fix up later */
2293 node.get_property (X_("orig-diskstream-id"), _orig_track_id);
2295 node.get_property (X_("orig-track-id"), _orig_track_id);
2296 node.get_property (X_("frozen"), _frozen);
2298 node.get_property (X_("combine-ops"), _combine_ops);
2301 if (node.get_property (X_("shared-with-ids"), shared_ids)) {
2302 if (!shared_ids.empty()) {
2303 vector<string> result;
2304 ::split (shared_ids, result, ',');
2305 vector<string>::iterator it = result.begin();
2306 for (; it != result.end(); ++it) {
2307 _shared_with_ids.push_back (PBD::ID(*it));
2314 nlist = node.children();
2316 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2320 if (child->name() == "Region") {
2322 seen_region_nodes = true;
2325 if (!child->get_property ("id", id)) {
2326 error << _("region state node has no ID, ignored") << endmsg;
2330 if ((region = region_by_id (id))) {
2332 region->suspend_property_changes ();
2334 if (region->set_state (*child, version)) {
2335 region->resume_property_changes ();
2339 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2340 region->suspend_property_changes ();
2342 error << _("Playlist: cannot create region from XML") << endmsg;
2347 RegionWriteLock rlock (this);
2348 add_region_internal (region, region->position());
2351 region->resume_property_changes ();
2356 if (seen_region_nodes && regions.empty()) {
2361 notify_contents_changed ();
2364 first_set_state = false;
2370 Playlist::get_state()
2372 return state (true);
2376 Playlist::get_template()
2378 return state (false);
2381 /** @param full_state true to include regions in the returned state, otherwise false.
2384 Playlist::state (bool full_state)
2386 XMLNode *node = new XMLNode (X_("Playlist"));
2388 node->set_property (X_("id"), id());
2389 node->set_property (X_("name"), name());
2390 node->set_property (X_("type"), _type);
2391 node->set_property (X_("orig-track-id"), _orig_track_id);
2394 list<PBD::ID>::const_iterator it = _shared_with_ids.begin();
2395 for (; it != _shared_with_ids.end(); ++it) {
2396 shared_ids += "," + (*it).to_s();
2398 if (!shared_ids.empty()) {
2399 shared_ids.erase(0,1);
2402 node->set_property (X_("shared-with-ids"), shared_ids);
2403 node->set_property (X_("frozen"), _frozen);
2406 RegionReadLock rlock (this);
2408 node->set_property ("combine-ops", _combine_ops);
2410 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2411 node->add_child_nocopy ((*i)->get_state());
2416 node->add_child_copy (*_extra_xml);
2423 Playlist::empty() const
2425 RegionReadLock rlock (const_cast<Playlist *>(this));
2426 return regions.empty();
2430 Playlist::n_regions() const
2432 RegionReadLock rlock (const_cast<Playlist *>(this));
2433 return regions.size();
2436 /** @return true if the all_regions list is empty, ie this playlist
2437 * has never had a region added to it.
2440 Playlist::all_regions_empty() const
2442 RegionReadLock rl (const_cast<Playlist *> (this));
2443 return all_regions.empty();
2446 pair<samplepos_t, samplepos_t>
2447 Playlist::get_extent () const
2449 RegionReadLock rlock (const_cast<Playlist *>(this));
2450 return _get_extent ();
2453 pair<samplepos_t, samplepos_t>
2454 Playlist::get_extent_with_endspace () const
2456 pair<samplepos_t, samplepos_t> l = get_extent();
2457 l.second += _end_space;
2461 pair<samplepos_t, samplepos_t>
2462 Playlist::_get_extent () const
2464 pair<samplepos_t, samplepos_t> ext (max_samplepos, 0);
2466 if (regions.empty()) {
2471 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2472 pair<samplepos_t, samplepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2473 if (e.first < ext.first) {
2474 ext.first = e.first;
2476 if (e.second > ext.second) {
2477 ext.second = e.second;
2485 Playlist::bump_name (string name, Session &session)
2487 string newname = name;
2490 newname = bump_name_once (newname, '.');
2491 } while (session.playlists()->by_name (newname)!=NULL);
2498 Playlist::top_layer() const
2500 RegionReadLock rlock (const_cast<Playlist *> (this));
2503 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2504 top = max (top, (*i)->layer());
2510 Playlist::set_edit_mode (EditMode mode)
2515 struct RelayerSort {
2516 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2517 return a->layering_index() < b->layering_index();
2521 /** Set a new layer for a region. This adjusts the layering indices of all
2522 * regions in the playlist to put the specified region in the appropriate
2523 * place. The actual layering will be fixed up when relayer() happens.
2526 Playlist::set_layer (boost::shared_ptr<Region> region, double new_layer)
2528 /* Remove the layer we are setting from our region list, and sort it
2529 * using the layer indeces.
2532 RegionList copy = regions.rlist();
2533 copy.remove (region);
2534 copy.sort (RelayerSort ());
2536 /* Put region back in the right place */
2537 RegionList::iterator i = copy.begin();
2538 while (i != copy.end ()) {
2539 if ((*i)->layer() > new_layer) {
2545 copy.insert (i, region);
2547 setup_layering_indices (copy);
2551 Playlist::setup_layering_indices (RegionList const & regions)
2555 for (RegionList::const_iterator k = regions.begin(); k != regions.end(); ++k) {
2556 (*k)->set_layering_index (j++);
2560 struct LaterHigherSort {
2561 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2562 return a->position() < b->position();
2566 /** Take the layering indices of each of our regions, compute the layers
2567 * that they should be on, and write the layers back to the regions.
2570 Playlist::relayer ()
2572 /* never compute layers when setting from XML */
2578 /* Build up a new list of regions on each layer, stored in a set of lists
2579 * each of which represent some period of time on some layer. The idea
2580 * is to avoid having to search the entire region list to establish whether
2581 * each region overlaps another */
2583 /* how many pieces to divide this playlist's time up into */
2584 int const divisions = 512;
2586 /* find the start and end positions of the regions on this playlist */
2587 samplepos_t start = INT64_MAX;
2588 samplepos_t end = 0;
2589 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2590 start = min (start, (*i)->position());
2591 end = max (end, (*i)->position() + (*i)->length());
2594 /* hence the size of each time division */
2595 double const division_size = (end - start) / double (divisions);
2597 vector<vector<RegionList> > layers;
2598 layers.push_back (vector<RegionList> (divisions));
2600 /* Sort our regions into layering index order (for manual layering) or position order (for later is higher)*/
2601 RegionList copy = regions.rlist();
2602 switch (Config->get_layer_model()) {
2604 copy.sort (LaterHigherSort ());
2607 copy.sort (RelayerSort ());
2611 DEBUG_TRACE (DEBUG::Layering, "relayer() using:\n");
2612 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2613 DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1 %2\n", (*i)->name(), (*i)->layering_index()));
2616 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2618 /* find the time divisions that this region covers; if there are no regions on the list,
2619 * division_size will equal 0 and in this case we'll just say that
2620 * start_division = end_division = 0.
2622 int start_division = 0;
2623 int end_division = 0;
2625 if (division_size > 0) {
2626 start_division = floor ( ((*i)->position() - start) / division_size);
2627 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2628 if (end_division == divisions) {
2633 assert (divisions == 0 || end_division < divisions);
2635 /* find the lowest layer that this region can go on */
2636 size_t j = layers.size();
2638 /* try layer j - 1; it can go on if it overlaps no other region
2639 * that is already on that layer
2642 bool overlap = false;
2643 for (int k = start_division; k <= end_division; ++k) {
2644 RegionList::iterator l = layers[j-1][k].begin ();
2645 while (l != layers[j-1][k].end()) {
2646 if ((*l)->overlap_equivalent (*i)) {
2659 /* overlap, so we must use layer j */
2666 if (j == layers.size()) {
2667 /* we need a new layer for this region */
2668 layers.push_back (vector<RegionList> (divisions));
2671 /* put a reference to this region in each of the divisions that it exists in */
2672 for (int k = start_division; k <= end_division; ++k) {
2673 layers[j][k].push_back (*i);
2676 (*i)->set_layer (j);
2679 /* It's a little tricky to know when we could avoid calling this; e.g. if we are
2680 * relayering because we just removed the only region on the top layer, nothing will
2681 * appear to have changed, but the StreamView must still sort itself out. We could
2682 * probably keep a note of the top layer last time we relayered, and check that,
2683 * but premature optimisation &c...
2685 notify_layering_changed ();
2687 /* This relayer() may have been called as a result of a region removal, in which
2688 * case we need to setup layering indices to account for the one that has just
2691 setup_layering_indices (copy);
2695 Playlist::raise_region (boost::shared_ptr<Region> region)
2697 set_layer (region, region->layer() + 1.5);
2702 Playlist::lower_region (boost::shared_ptr<Region> region)
2704 set_layer (region, region->layer() - 1.5);
2709 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2711 set_layer (region, DBL_MAX);
2716 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2718 set_layer (region, -0.5);
2723 Playlist::nudge_after (samplepos_t start, samplecnt_t distance, bool forwards)
2725 RegionList::iterator i;
2731 RegionWriteLock rlock (const_cast<Playlist *> (this));
2733 for (i = regions.begin(); i != regions.end(); ++i) {
2735 if ((*i)->position() >= start) {
2737 samplepos_t new_pos;
2741 if ((*i)->last_sample() > max_samplepos - distance) {
2742 new_pos = max_samplepos - (*i)->length();
2744 new_pos = (*i)->position() + distance;
2749 if ((*i)->position() > distance) {
2750 new_pos = (*i)->position() - distance;
2756 (*i)->set_position (new_pos);
2764 notify_contents_changed ();
2770 Playlist::uses_source (boost::shared_ptr<const Source> src, bool shallow) const
2772 RegionReadLock rlock (const_cast<Playlist*> (this));
2774 for (set<boost::shared_ptr<Region> >::const_iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
2775 /* Note: passing the second argument as false can cause at best
2776 * incredibly deep and time-consuming recursion, and at worst
2777 * cycles if the user has managed to create cycles of reference
2778 * between compound regions. We generally only this during
2779 * cleanup, and @param shallow is passed as true.
2781 if ((*r)->uses_source (src, shallow)) {
2790 boost::shared_ptr<Region>
2791 Playlist::find_region (const ID& id) const
2793 RegionReadLock rlock (const_cast<Playlist*> (this));
2795 /* searches all regions currently in use by the playlist */
2797 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2798 if ((*i)->id() == id) {
2803 return boost::shared_ptr<Region> ();
2807 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2809 RegionReadLock rlock (const_cast<Playlist*> (this));
2812 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2818 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
2819 for (RegionFactory::CompoundAssociations::iterator it = cassocs.begin(); it != cassocs.end(); ++it) {
2820 /* check if region is used in a compound */
2821 if (it->second == r) {
2822 /* region is referenced as 'original' of a compound */
2826 if (r->whole_file() && r->max_source_level() > 0) {
2827 /* region itself ia a compound.
2828 * the compound regions are not referenced -> check regions inside compound
2830 const SourceList& sl = r->sources();
2831 for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
2832 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource>(*s);
2834 if (ps->playlist()->region_use_count(it->first)) {
2835 // break out of both loops
2844 boost::shared_ptr<Region>
2845 Playlist::region_by_id (const ID& id) const
2847 /* searches all regions ever added to this playlist */
2849 for (set<boost::shared_ptr<Region> >::const_iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2850 if ((*i)->id() == id) {
2854 return boost::shared_ptr<Region> ();
2858 Playlist::dump () const
2860 boost::shared_ptr<Region> r;
2862 cerr << "Playlist \"" << _name << "\" " << endl
2863 << regions.size() << " regions "
2866 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2868 cerr << " " << r->name() << " ["
2869 << r->start() << "+" << r->length()
2879 Playlist::set_frozen (bool yn)
2885 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2889 if (region->locked()) {
2896 RegionWriteLock rlock (const_cast<Playlist*> (this));
2901 RegionList::iterator next;
2903 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2904 if ((*i) == region) {
2908 if (next != regions.end()) {
2910 if ((*next)->locked()) {
2914 samplepos_t new_pos;
2916 if ((*next)->position() != region->last_sample() + 1) {
2917 /* they didn't used to touch, so after shuffle,
2918 * just have them swap positions.
2920 new_pos = (*next)->position();
2922 /* they used to touch, so after shuffle,
2923 * make sure they still do. put the earlier
2924 * region where the later one will end after
2927 new_pos = region->position() + (*next)->length();
2930 (*next)->set_position (region->position());
2931 region->set_position (new_pos);
2933 /* avoid a full sort */
2935 regions.erase (i); // removes the region from the list */
2937 regions.insert (next, region); // adds it back after next
2946 RegionList::iterator prev = regions.end();
2948 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2949 if ((*i) == region) {
2951 if (prev != regions.end()) {
2953 if ((*prev)->locked()) {
2957 samplepos_t new_pos;
2958 if (region->position() != (*prev)->last_sample() + 1) {
2959 /* they didn't used to touch, so after shuffle,
2960 * just have them swap positions.
2962 new_pos = region->position();
2964 /* they used to touch, so after shuffle,
2965 * make sure they still do. put the earlier
2966 * one where the later one will end after
2968 new_pos = (*prev)->position() + region->length();
2971 region->set_position ((*prev)->position());
2972 (*prev)->set_position (new_pos);
2974 /* avoid a full sort */
2976 regions.erase (i); // remove region
2977 regions.insert (prev, region); // insert region before prev
2993 notify_contents_changed();
2999 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
3001 RegionReadLock rlock (const_cast<Playlist*> (this));
3003 if (regions.size() > 1) {
3011 Playlist::ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
3013 ripple_locked (at, distance, exclude);
3017 Playlist::update_after_tempo_map_change ()
3019 RegionWriteLock rlock (const_cast<Playlist*> (this));
3020 RegionList copy (regions.rlist());
3024 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
3025 (*i)->update_after_tempo_map_change ();
3027 /* possibly causes a contents changed notification (flush_notifications()) */
3032 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
3034 RegionReadLock rl (this);
3035 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3041 Playlist::has_region_at (samplepos_t const p) const
3043 RegionReadLock (const_cast<Playlist *> (this));
3045 RegionList::const_iterator i = regions.begin ();
3046 while (i != regions.end() && !(*i)->covers (p)) {
3050 return (i != regions.end());
3053 /** Look from a session sample time and find the start time of the next region
3054 * which is on the top layer of this playlist.
3055 * @param t Time to look from.
3056 * @return Position of next top-layered region, or max_samplepos if there isn't one.
3059 Playlist::find_next_top_layer_position (samplepos_t t) const
3061 RegionReadLock rlock (const_cast<Playlist *> (this));
3063 layer_t const top = top_layer ();
3065 RegionList copy = regions.rlist ();
3066 copy.sort (RegionSortByPosition ());
3068 for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3069 if ((*i)->position() >= t && (*i)->layer() == top) {
3070 return (*i)->position();
3074 return max_samplepos;
3077 boost::shared_ptr<Region>
3078 Playlist::combine (const RegionList& r)
3081 uint32_t channels = 0;
3083 samplepos_t earliest_position = max_samplepos;
3084 vector<TwoRegions> old_and_new_regions;
3085 vector<boost::shared_ptr<Region> > originals;
3086 vector<boost::shared_ptr<Region> > copies;
3089 uint32_t max_level = 0;
3091 /* find the maximum depth of all the regions we're combining */
3093 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3094 max_level = max (max_level, (*i)->max_source_level());
3097 parent_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, true);
3098 child_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, false);
3100 boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, parent_name, true);
3102 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3103 earliest_position = min (earliest_position, (*i)->position());
3106 /* enable this so that we do not try to create xfades etc. as we add
3110 pl->in_partition = true;
3112 /* sort by position then layer.
3113 * route_time_axis passes 'selected_regions' - which is not sorted.
3114 * here we need the top-most first, then every layer's region sorted by position.
3116 RegionList sorted(r);
3117 sorted.sort(RegionSortByLayerAndPosition());
3119 for (RegionList::const_iterator i = sorted.begin(); i != sorted.end(); ++i) {
3121 /* copy the region */
3123 boost::shared_ptr<Region> original_region = (*i);
3124 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
3126 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
3127 originals.push_back (original_region);
3128 copies.push_back (copied_region);
3130 RegionFactory::add_compound_association (original_region, copied_region);
3132 /* make position relative to zero */
3134 pl->add_region (copied_region, original_region->position() - earliest_position);
3135 copied_region->set_layer (original_region->layer ());
3137 /* use the maximum number of channels for any region */
3139 channels = max (channels, original_region->n_channels());
3141 /* it will go above the layer of the highest existing region */
3143 layer = max (layer, original_region->layer());
3146 pl->in_partition = false;
3148 pre_combine (copies);
3150 /* now create a new PlaylistSource for each channel in the new playlist */
3153 pair<samplepos_t,samplepos_t> extent = pl->get_extent();
3155 for (uint32_t chn = 0; chn < channels; ++chn) {
3156 sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, id(), parent_name, chn, 0, extent.second, false, false));
3160 /* now a new whole-file region using the list of sources */
3162 plist.add (Properties::start, 0);
3163 plist.add (Properties::length, extent.second);
3164 plist.add (Properties::name, parent_name);
3165 plist.add (Properties::whole_file, true);
3167 boost::shared_ptr<Region> parent_region = RegionFactory::create (sources, plist, true);
3169 /* now the non-whole-file region that we will actually use in the playlist */
3172 plist.add (Properties::start, 0);
3173 plist.add (Properties::length, extent.second);
3174 plist.add (Properties::name, child_name);
3175 plist.add (Properties::layer, layer+1);
3177 boost::shared_ptr<Region> compound_region = RegionFactory::create (parent_region, plist, true);
3179 /* remove all the selected regions from the current playlist */
3183 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3187 /* do type-specific stuff with the originals and the new compound region */
3189 post_combine (originals, compound_region);
3191 /* add the new region at the right location */
3193 add_region (compound_region, earliest_position);
3199 return compound_region;
3203 Playlist::uncombine (boost::shared_ptr<Region> target)
3205 boost::shared_ptr<PlaylistSource> pls;
3206 boost::shared_ptr<const Playlist> pl;
3207 vector<boost::shared_ptr<Region> > originals;
3208 vector<TwoRegions> old_and_new_regions;
3210 // (1) check that its really a compound region
3212 if ((pls = boost::dynamic_pointer_cast<PlaylistSource>(target->source (0))) == 0) {
3216 pl = pls->playlist();
3218 samplepos_t adjusted_start = 0; // gcc isn't smart enough
3219 samplepos_t adjusted_end = 0; // gcc isn't smart enough
3221 /* the leftmost (earliest) edge of the compound region
3222 * starts at zero in its source, or larger if it
3223 * has been trimmed or content-scrolled.
3225 * the rightmost (latest) edge of the compound region
3226 * relative to its source is the starting point plus
3227 * the length of the region.
3230 // (2) get all the original regions
3232 const RegionList& rl (pl->region_list_property().rlist());
3233 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
3234 sampleoffset_t move_offset = 0;
3236 /* there are two possibilities here:
3237 1) the playlist that the playlist source was based on
3238 is us, so just add the originals (which belonged to
3239 us anyway) back in the right place.
3241 2) the playlist that the playlist source was based on
3242 is NOT us, so we need to make copies of each of
3243 the original regions that we find, and add them
3246 bool same_playlist = (pls->original() == id());
3248 for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
3250 boost::shared_ptr<Region> current (*i);
3252 RegionFactory::CompoundAssociations::iterator ca = cassocs.find (*i);
3254 if (ca == cassocs.end()) {
3258 boost::shared_ptr<Region> original (ca->second);
3260 bool modified_region;
3262 if (i == rl.begin()) {
3263 move_offset = (target->position() - original->position()) - target->start();
3264 adjusted_start = original->position() + target->start();
3265 adjusted_end = adjusted_start + target->length();
3268 if (!same_playlist) {
3269 samplepos_t pos = original->position();
3270 /* make a copy, but don't announce it */
3271 original = RegionFactory::create (original, false);
3272 /* the pure copy constructor resets position() to zero, so fix that up. */
3273 original->set_position (pos);
3276 /* check to see how the original region (in the
3277 * playlist before compounding occurred) overlaps
3278 * with the new state of the compound region.
3281 original->clear_changes ();
3282 modified_region = false;
3284 switch (original->coverage (adjusted_start, adjusted_end)) {
3285 case Evoral::OverlapNone:
3286 /* original region does not cover any part
3287 * of the current state of the compound region
3291 case Evoral::OverlapInternal:
3292 /* overlap is just a small piece inside the
3293 * original so trim both ends
3295 original->trim_to (adjusted_start, adjusted_end - adjusted_start);
3296 modified_region = true;
3299 case Evoral::OverlapExternal:
3300 /* overlap fully covers original, so leave it as is */
3303 case Evoral::OverlapEnd:
3304 /* overlap starts within but covers end, so trim the front of the region */
3305 original->trim_front (adjusted_start);
3306 modified_region = true;
3309 case Evoral::OverlapStart:
3310 /* overlap covers start but ends within, so
3311 * trim the end of the region.
3313 original->trim_end (adjusted_end);
3314 modified_region = true;
3319 /* fix the position to match any movement of the compound region. */
3320 original->set_position (original->position() + move_offset);
3321 modified_region = true;
3324 if (modified_region) {
3325 _session.add_command (new StatefulDiffCommand (original));
3328 /* and add to the list of regions waiting to be
3332 originals.push_back (original);
3333 old_and_new_regions.push_back (TwoRegions (*i, original));
3336 pre_uncombine (originals, target);
3338 in_partition = true;
3341 // (3) remove the compound region
3343 remove_region (target);
3345 // (4) add the constituent regions
3347 for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
3348 add_region ((*i), (*i)->position());
3349 set_layer((*i), (*i)->layer());
3350 if (!RegionFactory::region_by_id((*i)->id())) {
3351 RegionFactory::map_add(*i);
3355 in_partition = false;
3360 Playlist::fade_range (list<AudioRange>& ranges)
3362 RegionReadLock rlock (this);
3363 for (list<AudioRange>::iterator r = ranges.begin(); r != ranges.end(); ) {
3364 list<AudioRange>::iterator tmpr = r;
3366 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ) {
3367 RegionList::const_iterator tmpi = i;
3369 (*i)->fade_range ((*r).start, (*r).end);
3377 Playlist::max_source_level () const
3379 RegionReadLock rlock (const_cast<Playlist *> (this));
3382 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3383 lvl = max (lvl, (*i)->max_source_level());
3390 Playlist::set_orig_track_id (const PBD::ID& id)
3392 if (shared_with(id)) {
3393 // Swap 'shared_id' / origin_track_id
3395 share_with (_orig_track_id);
3397 _orig_track_id = id;
3401 Playlist::share_with (const PBD::ID& id)
3403 if (!shared_with(id)) {
3404 _shared_with_ids.push_back (id);
3409 Playlist::unshare_with (const PBD::ID& id)
3411 list<PBD::ID>::iterator it = _shared_with_ids.begin ();
3412 while (it != _shared_with_ids.end()) {
3414 _shared_with_ids.erase (it);
3422 Playlist::shared_with (const PBD::ID& id) const
3424 bool shared = false;
3425 list<PBD::ID>::const_iterator it = _shared_with_ids.begin ();
3426 while (it != _shared_with_ids.end() && !shared) {
3437 Playlist::reset_shares ()
3439 _shared_with_ids.clear();
3442 /** Take a list of ranges, coalesce any that can be coalesced, then call
3443 * check_crossfades for each one.
3446 Playlist::coalesce_and_check_crossfades (list<Evoral::Range<samplepos_t> > ranges)
3448 /* XXX: it's a shame that this coalesce algorithm also exists in
3449 * TimeSelection::consolidate().
3452 /* XXX: xfade: this is implemented in Evoral::RangeList */
3455 for (list<Evoral::Range<samplepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
3456 for (list<Evoral::Range<samplepos_t> >::iterator j = ranges.begin(); j != ranges.end(); ++j) {
3462 // XXX i->from can be > i->to - is this right? coverage() will return OverlapNone in this case
3463 if (Evoral::coverage (i->from, i->to, j->from, j->to) != Evoral::OverlapNone) {
3464 i->from = min (i->from, j->from);
3465 i->to = max (i->to, j->to);
3474 Playlist::set_capture_insertion_in_progress (bool yn)
3476 _capture_insertion_underway = yn;