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::position) && !what_changed.contains (Properties::length)) {
1790 notify_region_moved (region);
1791 } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1792 notify_region_end_trimmed (region);
1793 } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1794 notify_region_start_trimmed (region);
1797 /* don't notify about layer changes, since we are the only object that can initiate
1798 * them, and we notify in ::relayer()
1801 if (what_changed.contains (our_interests)) {
1805 if (send_contents || save) {
1806 notify_contents_changed ();
1809 mark_session_dirty ();
1815 Playlist::drop_regions ()
1817 RegionWriteLock rl (this);
1819 all_regions.clear ();
1823 Playlist::sync_all_regions_with_regions ()
1825 RegionWriteLock rl (this);
1827 all_regions.clear ();
1829 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1830 all_regions.insert (*i);
1835 Playlist::clear (bool with_signals)
1838 RegionWriteLock rl (this);
1840 region_state_changed_connections.drop_connections ();
1841 region_drop_references_connections.drop_connections ();
1843 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1844 pending_removes.insert (*i);
1849 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1850 remove_dependents (*s);
1856 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1857 RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1860 pending_removes.clear ();
1861 pending_contents_change = false;
1867 /* *********************************************************************
1869 **********************************************************************/
1871 boost::shared_ptr<RegionList>
1872 Playlist::region_list()
1874 RegionReadLock rlock (this);
1875 boost::shared_ptr<RegionList> rlist (new RegionList (regions.rlist ()));
1880 Playlist::deep_sources (std::set<boost::shared_ptr<Source> >& sources) const
1882 RegionReadLock rlock (const_cast<Playlist*>(this));
1884 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1885 (*i)->deep_sources (sources);
1889 boost::shared_ptr<RegionList>
1890 Playlist::regions_at (samplepos_t sample)
1892 RegionReadLock rlock (this);
1893 return find_regions_at (sample);
1897 Playlist::count_regions_at (samplepos_t sample) const
1899 RegionReadLock rlock (const_cast<Playlist*>(this));
1902 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1903 if ((*i)->covers (sample)) {
1911 boost::shared_ptr<Region>
1912 Playlist::top_region_at (samplepos_t sample)
1914 RegionReadLock rlock (this);
1915 boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1916 boost::shared_ptr<Region> region;
1918 if (rlist->size()) {
1919 RegionSortByLayer cmp;
1921 region = rlist->back();
1927 boost::shared_ptr<Region>
1928 Playlist::top_unmuted_region_at (samplepos_t sample)
1930 RegionReadLock rlock (this);
1931 boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1933 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1935 RegionList::iterator tmp = i;
1939 if ((*i)->muted()) {
1946 boost::shared_ptr<Region> region;
1948 if (rlist->size()) {
1949 RegionSortByLayer cmp;
1951 region = rlist->back();
1957 boost::shared_ptr<RegionList>
1958 Playlist::find_regions_at (samplepos_t sample)
1960 /* Caller must hold lock */
1962 boost::shared_ptr<RegionList> rlist (new RegionList);
1964 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1965 if ((*i)->covers (sample)) {
1966 rlist->push_back (*i);
1973 boost::shared_ptr<RegionList>
1974 Playlist::regions_with_start_within (Evoral::Range<samplepos_t> range)
1976 RegionReadLock rlock (this);
1977 boost::shared_ptr<RegionList> rlist (new RegionList);
1979 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1980 if ((*i)->first_sample() >= range.from && (*i)->first_sample() <= range.to) {
1981 rlist->push_back (*i);
1988 boost::shared_ptr<RegionList>
1989 Playlist::regions_with_end_within (Evoral::Range<samplepos_t> range)
1991 RegionReadLock rlock (this);
1992 boost::shared_ptr<RegionList> rlist (new RegionList);
1994 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1995 if ((*i)->last_sample() >= range.from && (*i)->last_sample() <= range.to) {
1996 rlist->push_back (*i);
2003 boost::shared_ptr<RegionList>
2004 Playlist::regions_touched (samplepos_t start, samplepos_t end)
2006 RegionReadLock rlock (this);
2007 return regions_touched_locked (start, end);
2010 boost::shared_ptr<RegionList>
2011 Playlist::regions_touched_locked (samplepos_t start, samplepos_t end)
2013 boost::shared_ptr<RegionList> rlist (new RegionList);
2015 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2016 if ((*i)->coverage (start, end) != Evoral::OverlapNone) {
2017 rlist->push_back (*i);
2025 Playlist::find_next_transient (samplepos_t from, int dir)
2027 RegionReadLock rlock (this);
2028 AnalysisFeatureList points;
2029 AnalysisFeatureList these_points;
2031 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2033 if ((*i)->last_sample() < from) {
2037 if ((*i)->first_sample() > from) {
2042 (*i)->get_transients (these_points);
2044 /* add first sample, just, err, because */
2046 these_points.push_back ((*i)->first_sample());
2048 points.insert (points.end(), these_points.begin(), these_points.end());
2049 these_points.clear ();
2052 if (points.empty()) {
2056 TransientDetector::cleanup_transients (points, _session.sample_rate(), 3.0);
2057 bool reached = false;
2060 for (AnalysisFeatureList::const_iterator x = points.begin(); x != points.end(); ++x) {
2065 if (reached && (*x) > from) {
2070 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2075 if (reached && (*x) < from) {
2084 boost::shared_ptr<Region>
2085 Playlist::find_next_region (samplepos_t sample, RegionPoint point, int dir)
2087 RegionReadLock rlock (this);
2088 boost::shared_ptr<Region> ret;
2089 samplepos_t closest = max_samplepos;
2091 bool end_iter = false;
2093 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2097 sampleoffset_t distance;
2098 boost::shared_ptr<Region> r = (*i);
2099 samplepos_t pos = 0;
2103 pos = r->first_sample ();
2106 pos = r->last_sample ();
2109 pos = r->sync_position ();
2114 case 1: /* forwards */
2117 if ((distance = pos - sample) < closest) {
2126 default: /* backwards */
2129 if ((distance = sample - pos) < closest) {
2145 Playlist::find_next_region_boundary (samplepos_t sample, int dir)
2147 RegionReadLock rlock (this);
2149 samplepos_t closest = max_samplepos;
2150 samplepos_t ret = -1;
2154 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2156 boost::shared_ptr<Region> r = (*i);
2157 sampleoffset_t distance;
2158 const samplepos_t first_sample = r->first_sample();
2159 const samplepos_t last_sample = r->last_sample();
2161 if (first_sample > sample) {
2163 distance = first_sample - sample;
2165 if (distance < closest) {
2171 if (last_sample > sample) {
2173 distance = last_sample - sample;
2175 if (distance < closest) {
2184 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2186 boost::shared_ptr<Region> r = (*i);
2187 sampleoffset_t distance;
2188 const samplepos_t first_sample = r->first_sample();
2189 const samplepos_t last_sample = r->last_sample();
2191 if (last_sample < sample) {
2193 distance = sample - last_sample;
2195 if (distance < closest) {
2201 if (first_sample < sample) {
2203 distance = sample - first_sample;
2205 if (distance < closest) {
2216 /***********************************************************************/
2219 Playlist::mark_session_dirty ()
2221 if (!in_set_state && !holding_state ()) {
2222 _session.set_dirty();
2227 Playlist::rdiff (vector<Command*>& cmds) const
2229 RegionReadLock rlock (const_cast<Playlist *> (this));
2230 Stateful::rdiff (cmds);
2234 Playlist::clear_owned_changes ()
2236 RegionReadLock rlock (this);
2237 Stateful::clear_owned_changes ();
2241 Playlist::update (const RegionListProperty::ChangeRecord& change)
2243 DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2244 name(), change.added.size(), change.removed.size()));
2247 /* add the added regions */
2248 for (RegionListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
2249 add_region_internal ((*i), (*i)->position());
2251 /* remove the removed regions */
2252 for (RegionListProperty::ChangeContainer::const_iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2260 Playlist::set_state (const XMLNode& node, int version)
2264 XMLNodeConstIterator niter;
2265 XMLPropertyConstIterator piter;
2266 boost::shared_ptr<Region> region;
2268 bool seen_region_nodes = false;
2273 if (node.name() != "Playlist") {
2283 if (node.get_property (X_("name"), name)) {
2288 /* XXX legacy session: fix up later */
2289 node.get_property (X_("orig-diskstream-id"), _orig_track_id);
2291 node.get_property (X_("orig-track-id"), _orig_track_id);
2292 node.get_property (X_("frozen"), _frozen);
2294 node.get_property (X_("combine-ops"), _combine_ops);
2297 if (node.get_property (X_("shared-with-ids"), shared_ids)) {
2298 if (!shared_ids.empty()) {
2299 vector<string> result;
2300 ::split (shared_ids, result, ',');
2301 vector<string>::iterator it = result.begin();
2302 for (; it != result.end(); ++it) {
2303 _shared_with_ids.push_back (PBD::ID(*it));
2310 nlist = node.children();
2312 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2316 if (child->name() == "Region") {
2318 seen_region_nodes = true;
2321 if (!child->get_property ("id", id)) {
2322 error << _("region state node has no ID, ignored") << endmsg;
2326 if ((region = region_by_id (id))) {
2328 region->suspend_property_changes ();
2330 if (region->set_state (*child, version)) {
2331 region->resume_property_changes ();
2335 } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2336 region->suspend_property_changes ();
2338 error << _("Playlist: cannot create region from XML") << endmsg;
2343 RegionWriteLock rlock (this);
2344 add_region_internal (region, region->position());
2347 region->resume_property_changes ();
2352 if (seen_region_nodes && regions.empty()) {
2357 notify_contents_changed ();
2360 first_set_state = false;
2366 Playlist::get_state()
2368 return state (true);
2372 Playlist::get_template()
2374 return state (false);
2377 /** @param full_state true to include regions in the returned state, otherwise false.
2380 Playlist::state (bool full_state)
2382 XMLNode *node = new XMLNode (X_("Playlist"));
2384 node->set_property (X_("id"), id());
2385 node->set_property (X_("name"), name());
2386 node->set_property (X_("type"), _type);
2387 node->set_property (X_("orig-track-id"), _orig_track_id);
2390 list<PBD::ID>::const_iterator it = _shared_with_ids.begin();
2391 for (; it != _shared_with_ids.end(); ++it) {
2392 shared_ids += "," + (*it).to_s();
2394 if (!shared_ids.empty()) {
2395 shared_ids.erase(0,1);
2398 node->set_property (X_("shared-with-ids"), shared_ids);
2399 node->set_property (X_("frozen"), _frozen);
2402 RegionReadLock rlock (this);
2404 node->set_property ("combine-ops", _combine_ops);
2406 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2407 node->add_child_nocopy ((*i)->get_state());
2412 node->add_child_copy (*_extra_xml);
2419 Playlist::empty() const
2421 RegionReadLock rlock (const_cast<Playlist *>(this));
2422 return regions.empty();
2426 Playlist::n_regions() const
2428 RegionReadLock rlock (const_cast<Playlist *>(this));
2429 return regions.size();
2432 /** @return true if the all_regions list is empty, ie this playlist
2433 * has never had a region added to it.
2436 Playlist::all_regions_empty() const
2438 RegionReadLock rl (const_cast<Playlist *> (this));
2439 return all_regions.empty();
2442 pair<samplepos_t, samplepos_t>
2443 Playlist::get_extent () const
2445 RegionReadLock rlock (const_cast<Playlist *>(this));
2446 return _get_extent ();
2449 pair<samplepos_t, samplepos_t>
2450 Playlist::get_extent_with_endspace () const
2452 pair<samplepos_t, samplepos_t> l = get_extent();
2453 l.second += _end_space;
2457 pair<samplepos_t, samplepos_t>
2458 Playlist::_get_extent () const
2460 pair<samplepos_t, samplepos_t> ext (max_samplepos, 0);
2462 if (regions.empty()) {
2467 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2468 pair<samplepos_t, samplepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2469 if (e.first < ext.first) {
2470 ext.first = e.first;
2472 if (e.second > ext.second) {
2473 ext.second = e.second;
2481 Playlist::bump_name (string name, Session &session)
2483 string newname = name;
2486 newname = bump_name_once (newname, '.');
2487 } while (session.playlists()->by_name (newname)!=NULL);
2494 Playlist::top_layer() const
2496 RegionReadLock rlock (const_cast<Playlist *> (this));
2499 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2500 top = max (top, (*i)->layer());
2506 Playlist::set_edit_mode (EditMode mode)
2511 struct RelayerSort {
2512 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2513 return a->layering_index() < b->layering_index();
2517 /** Set a new layer for a region. This adjusts the layering indices of all
2518 * regions in the playlist to put the specified region in the appropriate
2519 * place. The actual layering will be fixed up when relayer() happens.
2522 Playlist::set_layer (boost::shared_ptr<Region> region, double new_layer)
2524 /* Remove the layer we are setting from our region list, and sort it
2525 * using the layer indeces.
2528 RegionList copy = regions.rlist();
2529 copy.remove (region);
2530 copy.sort (RelayerSort ());
2532 /* Put region back in the right place */
2533 RegionList::iterator i = copy.begin();
2534 while (i != copy.end ()) {
2535 if ((*i)->layer() > new_layer) {
2541 copy.insert (i, region);
2543 setup_layering_indices (copy);
2547 Playlist::setup_layering_indices (RegionList const & regions)
2551 for (RegionList::const_iterator k = regions.begin(); k != regions.end(); ++k) {
2552 (*k)->set_layering_index (j++);
2556 struct LaterHigherSort {
2557 bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2558 return a->position() < b->position();
2562 /** Take the layering indices of each of our regions, compute the layers
2563 * that they should be on, and write the layers back to the regions.
2566 Playlist::relayer ()
2568 /* never compute layers when setting from XML */
2574 /* Build up a new list of regions on each layer, stored in a set of lists
2575 * each of which represent some period of time on some layer. The idea
2576 * is to avoid having to search the entire region list to establish whether
2577 * each region overlaps another */
2579 /* how many pieces to divide this playlist's time up into */
2580 int const divisions = 512;
2582 /* find the start and end positions of the regions on this playlist */
2583 samplepos_t start = INT64_MAX;
2584 samplepos_t end = 0;
2585 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2586 start = min (start, (*i)->position());
2587 end = max (end, (*i)->position() + (*i)->length());
2590 /* hence the size of each time division */
2591 double const division_size = (end - start) / double (divisions);
2593 vector<vector<RegionList> > layers;
2594 layers.push_back (vector<RegionList> (divisions));
2596 /* Sort our regions into layering index order (for manual layering) or position order (for later is higher)*/
2597 RegionList copy = regions.rlist();
2598 switch (Config->get_layer_model()) {
2600 copy.sort (LaterHigherSort ());
2603 copy.sort (RelayerSort ());
2607 DEBUG_TRACE (DEBUG::Layering, "relayer() using:\n");
2608 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2609 DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1 %2\n", (*i)->name(), (*i)->layering_index()));
2612 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2614 /* find the time divisions that this region covers; if there are no regions on the list,
2615 * division_size will equal 0 and in this case we'll just say that
2616 * start_division = end_division = 0.
2618 int start_division = 0;
2619 int end_division = 0;
2621 if (division_size > 0) {
2622 start_division = floor ( ((*i)->position() - start) / division_size);
2623 end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2624 if (end_division == divisions) {
2629 assert (divisions == 0 || end_division < divisions);
2631 /* find the lowest layer that this region can go on */
2632 size_t j = layers.size();
2634 /* try layer j - 1; it can go on if it overlaps no other region
2635 * that is already on that layer
2638 bool overlap = false;
2639 for (int k = start_division; k <= end_division; ++k) {
2640 RegionList::iterator l = layers[j-1][k].begin ();
2641 while (l != layers[j-1][k].end()) {
2642 if ((*l)->overlap_equivalent (*i)) {
2655 /* overlap, so we must use layer j */
2662 if (j == layers.size()) {
2663 /* we need a new layer for this region */
2664 layers.push_back (vector<RegionList> (divisions));
2667 /* put a reference to this region in each of the divisions that it exists in */
2668 for (int k = start_division; k <= end_division; ++k) {
2669 layers[j][k].push_back (*i);
2672 (*i)->set_layer (j);
2675 /* It's a little tricky to know when we could avoid calling this; e.g. if we are
2676 * relayering because we just removed the only region on the top layer, nothing will
2677 * appear to have changed, but the StreamView must still sort itself out. We could
2678 * probably keep a note of the top layer last time we relayered, and check that,
2679 * but premature optimisation &c...
2681 notify_layering_changed ();
2683 /* This relayer() may have been called as a result of a region removal, in which
2684 * case we need to setup layering indices to account for the one that has just
2687 setup_layering_indices (copy);
2691 Playlist::raise_region (boost::shared_ptr<Region> region)
2693 set_layer (region, region->layer() + 1.5);
2698 Playlist::lower_region (boost::shared_ptr<Region> region)
2700 set_layer (region, region->layer() - 1.5);
2705 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2707 set_layer (region, DBL_MAX);
2712 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2714 set_layer (region, -0.5);
2719 Playlist::nudge_after (samplepos_t start, samplecnt_t distance, bool forwards)
2721 RegionList::iterator i;
2727 RegionWriteLock rlock (const_cast<Playlist *> (this));
2729 for (i = regions.begin(); i != regions.end(); ++i) {
2731 if ((*i)->position() >= start) {
2733 samplepos_t new_pos;
2737 if ((*i)->last_sample() > max_samplepos - distance) {
2738 new_pos = max_samplepos - (*i)->length();
2740 new_pos = (*i)->position() + distance;
2745 if ((*i)->position() > distance) {
2746 new_pos = (*i)->position() - distance;
2752 (*i)->set_position (new_pos);
2760 notify_contents_changed ();
2766 Playlist::uses_source (boost::shared_ptr<const Source> src, bool shallow) const
2768 RegionReadLock rlock (const_cast<Playlist*> (this));
2770 for (set<boost::shared_ptr<Region> >::const_iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
2771 /* Note: passing the second argument as false can cause at best
2772 * incredibly deep and time-consuming recursion, and at worst
2773 * cycles if the user has managed to create cycles of reference
2774 * between compound regions. We generally only this during
2775 * cleanup, and @param shallow is passed as true.
2777 if ((*r)->uses_source (src, shallow)) {
2786 boost::shared_ptr<Region>
2787 Playlist::find_region (const ID& id) const
2789 RegionReadLock rlock (const_cast<Playlist*> (this));
2791 /* searches all regions currently in use by the playlist */
2793 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2794 if ((*i)->id() == id) {
2799 return boost::shared_ptr<Region> ();
2803 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2805 RegionReadLock rlock (const_cast<Playlist*> (this));
2808 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2814 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
2815 for (RegionFactory::CompoundAssociations::iterator it = cassocs.begin(); it != cassocs.end(); ++it) {
2816 /* check if region is used in a compound */
2817 if (it->second == r) {
2818 /* region is referenced as 'original' of a compound */
2822 if (r->whole_file() && r->max_source_level() > 0) {
2823 /* region itself ia a compound.
2824 * the compound regions are not referenced -> check regions inside compound
2826 const SourceList& sl = r->sources();
2827 for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
2828 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource>(*s);
2830 if (ps->playlist()->region_use_count(it->first)) {
2831 // break out of both loops
2840 boost::shared_ptr<Region>
2841 Playlist::region_by_id (const ID& id) const
2843 /* searches all regions ever added to this playlist */
2845 for (set<boost::shared_ptr<Region> >::const_iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2846 if ((*i)->id() == id) {
2850 return boost::shared_ptr<Region> ();
2854 Playlist::dump () const
2856 boost::shared_ptr<Region> r;
2858 cerr << "Playlist \"" << _name << "\" " << endl
2859 << regions.size() << " regions "
2862 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2864 cerr << " " << r->name() << " ["
2865 << r->start() << "+" << r->length()
2875 Playlist::set_frozen (bool yn)
2881 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2885 if (region->locked()) {
2892 RegionWriteLock rlock (const_cast<Playlist*> (this));
2897 RegionList::iterator next;
2899 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2900 if ((*i) == region) {
2904 if (next != regions.end()) {
2906 if ((*next)->locked()) {
2910 samplepos_t new_pos;
2912 if ((*next)->position() != region->last_sample() + 1) {
2913 /* they didn't used to touch, so after shuffle,
2914 * just have them swap positions.
2916 new_pos = (*next)->position();
2918 /* they used to touch, so after shuffle,
2919 * make sure they still do. put the earlier
2920 * region where the later one will end after
2923 new_pos = region->position() + (*next)->length();
2926 (*next)->set_position (region->position());
2927 region->set_position (new_pos);
2929 /* avoid a full sort */
2931 regions.erase (i); // removes the region from the list */
2933 regions.insert (next, region); // adds it back after next
2942 RegionList::iterator prev = regions.end();
2944 for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2945 if ((*i) == region) {
2947 if (prev != regions.end()) {
2949 if ((*prev)->locked()) {
2953 samplepos_t new_pos;
2954 if (region->position() != (*prev)->last_sample() + 1) {
2955 /* they didn't used to touch, so after shuffle,
2956 * just have them swap positions.
2958 new_pos = region->position();
2960 /* they used to touch, so after shuffle,
2961 * make sure they still do. put the earlier
2962 * one where the later one will end after
2964 new_pos = (*prev)->position() + region->length();
2967 region->set_position ((*prev)->position());
2968 (*prev)->set_position (new_pos);
2970 /* avoid a full sort */
2972 regions.erase (i); // remove region
2973 regions.insert (prev, region); // insert region before prev
2989 notify_contents_changed();
2995 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2997 RegionReadLock rlock (const_cast<Playlist*> (this));
2999 if (regions.size() > 1) {
3007 Playlist::ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
3009 ripple_locked (at, distance, exclude);
3013 Playlist::update_after_tempo_map_change ()
3015 RegionWriteLock rlock (const_cast<Playlist*> (this));
3016 RegionList copy (regions.rlist());
3020 for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
3021 (*i)->update_after_tempo_map_change ();
3023 /* possibly causes a contents changed notification (flush_notifications()) */
3028 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
3030 RegionReadLock rl (this);
3031 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3037 Playlist::has_region_at (samplepos_t const p) const
3039 RegionReadLock (const_cast<Playlist *> (this));
3041 RegionList::const_iterator i = regions.begin ();
3042 while (i != regions.end() && !(*i)->covers (p)) {
3046 return (i != regions.end());
3049 /** Look from a session sample time and find the start time of the next region
3050 * which is on the top layer of this playlist.
3051 * @param t Time to look from.
3052 * @return Position of next top-layered region, or max_samplepos if there isn't one.
3055 Playlist::find_next_top_layer_position (samplepos_t t) const
3057 RegionReadLock rlock (const_cast<Playlist *> (this));
3059 layer_t const top = top_layer ();
3061 RegionList copy = regions.rlist ();
3062 copy.sort (RegionSortByPosition ());
3064 for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3065 if ((*i)->position() >= t && (*i)->layer() == top) {
3066 return (*i)->position();
3070 return max_samplepos;
3073 boost::shared_ptr<Region>
3074 Playlist::combine (const RegionList& r)
3077 uint32_t channels = 0;
3079 samplepos_t earliest_position = max_samplepos;
3080 vector<TwoRegions> old_and_new_regions;
3081 vector<boost::shared_ptr<Region> > originals;
3082 vector<boost::shared_ptr<Region> > copies;
3085 uint32_t max_level = 0;
3087 /* find the maximum depth of all the regions we're combining */
3089 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3090 max_level = max (max_level, (*i)->max_source_level());
3093 parent_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, true);
3094 child_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, false);
3096 boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, parent_name, true);
3098 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3099 earliest_position = min (earliest_position, (*i)->position());
3102 /* enable this so that we do not try to create xfades etc. as we add
3106 pl->in_partition = true;
3108 /* sort by position then layer.
3109 * route_time_axis passes 'selected_regions' - which is not sorted.
3110 * here we need the top-most first, then every layer's region sorted by position.
3112 RegionList sorted(r);
3113 sorted.sort(RegionSortByLayerAndPosition());
3115 for (RegionList::const_iterator i = sorted.begin(); i != sorted.end(); ++i) {
3117 /* copy the region */
3119 boost::shared_ptr<Region> original_region = (*i);
3120 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
3122 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
3123 originals.push_back (original_region);
3124 copies.push_back (copied_region);
3126 RegionFactory::add_compound_association (original_region, copied_region);
3128 /* make position relative to zero */
3130 pl->add_region (copied_region, original_region->position() - earliest_position);
3131 copied_region->set_layer (original_region->layer ());
3133 /* use the maximum number of channels for any region */
3135 channels = max (channels, original_region->n_channels());
3137 /* it will go above the layer of the highest existing region */
3139 layer = max (layer, original_region->layer());
3142 pl->in_partition = false;
3144 pre_combine (copies);
3146 /* now create a new PlaylistSource for each channel in the new playlist */
3149 pair<samplepos_t,samplepos_t> extent = pl->get_extent();
3151 for (uint32_t chn = 0; chn < channels; ++chn) {
3152 sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, id(), parent_name, chn, 0, extent.second, false, false));
3156 /* now a new whole-file region using the list of sources */
3158 plist.add (Properties::start, 0);
3159 plist.add (Properties::length, extent.second);
3160 plist.add (Properties::name, parent_name);
3161 plist.add (Properties::whole_file, true);
3163 boost::shared_ptr<Region> parent_region = RegionFactory::create (sources, plist, true);
3165 /* now the non-whole-file region that we will actually use in the playlist */
3168 plist.add (Properties::start, 0);
3169 plist.add (Properties::length, extent.second);
3170 plist.add (Properties::name, child_name);
3171 plist.add (Properties::layer, layer+1);
3173 boost::shared_ptr<Region> compound_region = RegionFactory::create (parent_region, plist, true);
3175 /* remove all the selected regions from the current playlist */
3179 for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3183 /* do type-specific stuff with the originals and the new compound region */
3185 post_combine (originals, compound_region);
3187 /* add the new region at the right location */
3189 add_region (compound_region, earliest_position);
3195 return compound_region;
3199 Playlist::uncombine (boost::shared_ptr<Region> target)
3201 boost::shared_ptr<PlaylistSource> pls;
3202 boost::shared_ptr<const Playlist> pl;
3203 vector<boost::shared_ptr<Region> > originals;
3204 vector<TwoRegions> old_and_new_regions;
3206 // (1) check that its really a compound region
3208 if ((pls = boost::dynamic_pointer_cast<PlaylistSource>(target->source (0))) == 0) {
3212 pl = pls->playlist();
3214 samplepos_t adjusted_start = 0; // gcc isn't smart enough
3215 samplepos_t adjusted_end = 0; // gcc isn't smart enough
3217 /* the leftmost (earliest) edge of the compound region
3218 * starts at zero in its source, or larger if it
3219 * has been trimmed or content-scrolled.
3221 * the rightmost (latest) edge of the compound region
3222 * relative to its source is the starting point plus
3223 * the length of the region.
3226 // (2) get all the original regions
3228 const RegionList& rl (pl->region_list_property().rlist());
3229 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
3230 sampleoffset_t move_offset = 0;
3232 /* there are two possibilities here:
3233 1) the playlist that the playlist source was based on
3234 is us, so just add the originals (which belonged to
3235 us anyway) back in the right place.
3237 2) the playlist that the playlist source was based on
3238 is NOT us, so we need to make copies of each of
3239 the original regions that we find, and add them
3242 bool same_playlist = (pls->original() == id());
3244 for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
3246 boost::shared_ptr<Region> current (*i);
3248 RegionFactory::CompoundAssociations::iterator ca = cassocs.find (*i);
3250 if (ca == cassocs.end()) {
3254 boost::shared_ptr<Region> original (ca->second);
3256 bool modified_region;
3258 if (i == rl.begin()) {
3259 move_offset = (target->position() - original->position()) - target->start();
3260 adjusted_start = original->position() + target->start();
3261 adjusted_end = adjusted_start + target->length();
3264 if (!same_playlist) {
3265 samplepos_t pos = original->position();
3266 /* make a copy, but don't announce it */
3267 original = RegionFactory::create (original, false);
3268 /* the pure copy constructor resets position() to zero, so fix that up. */
3269 original->set_position (pos);
3272 /* check to see how the original region (in the
3273 * playlist before compounding occurred) overlaps
3274 * with the new state of the compound region.
3277 original->clear_changes ();
3278 modified_region = false;
3280 switch (original->coverage (adjusted_start, adjusted_end)) {
3281 case Evoral::OverlapNone:
3282 /* original region does not cover any part
3283 * of the current state of the compound region
3287 case Evoral::OverlapInternal:
3288 /* overlap is just a small piece inside the
3289 * original so trim both ends
3291 original->trim_to (adjusted_start, adjusted_end - adjusted_start);
3292 modified_region = true;
3295 case Evoral::OverlapExternal:
3296 /* overlap fully covers original, so leave it as is */
3299 case Evoral::OverlapEnd:
3300 /* overlap starts within but covers end, so trim the front of the region */
3301 original->trim_front (adjusted_start);
3302 modified_region = true;
3305 case Evoral::OverlapStart:
3306 /* overlap covers start but ends within, so
3307 * trim the end of the region.
3309 original->trim_end (adjusted_end);
3310 modified_region = true;
3315 /* fix the position to match any movement of the compound region. */
3316 original->set_position (original->position() + move_offset);
3317 modified_region = true;
3320 if (modified_region) {
3321 _session.add_command (new StatefulDiffCommand (original));
3324 /* and add to the list of regions waiting to be
3328 originals.push_back (original);
3329 old_and_new_regions.push_back (TwoRegions (*i, original));
3332 pre_uncombine (originals, target);
3334 in_partition = true;
3337 // (3) remove the compound region
3339 remove_region (target);
3341 // (4) add the constituent regions
3343 for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
3344 add_region ((*i), (*i)->position());
3345 set_layer((*i), (*i)->layer());
3346 if (!RegionFactory::region_by_id((*i)->id())) {
3347 RegionFactory::map_add(*i);
3351 in_partition = false;
3356 Playlist::fade_range (list<AudioRange>& ranges)
3358 RegionReadLock rlock (this);
3359 for (list<AudioRange>::iterator r = ranges.begin(); r != ranges.end(); ) {
3360 list<AudioRange>::iterator tmpr = r;
3362 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ) {
3363 RegionList::const_iterator tmpi = i;
3365 (*i)->fade_range ((*r).start, (*r).end);
3373 Playlist::max_source_level () const
3375 RegionReadLock rlock (const_cast<Playlist *> (this));
3378 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3379 lvl = max (lvl, (*i)->max_source_level());
3386 Playlist::set_orig_track_id (const PBD::ID& id)
3388 if (shared_with(id)) {
3389 // Swap 'shared_id' / origin_track_id
3391 share_with (_orig_track_id);
3393 _orig_track_id = id;
3397 Playlist::share_with (const PBD::ID& id)
3399 if (!shared_with(id)) {
3400 _shared_with_ids.push_back (id);
3405 Playlist::unshare_with (const PBD::ID& id)
3407 list<PBD::ID>::iterator it = _shared_with_ids.begin ();
3408 while (it != _shared_with_ids.end()) {
3410 _shared_with_ids.erase (it);
3418 Playlist::shared_with (const PBD::ID& id) const
3420 bool shared = false;
3421 list<PBD::ID>::const_iterator it = _shared_with_ids.begin ();
3422 while (it != _shared_with_ids.end() && !shared) {
3433 Playlist::reset_shares ()
3435 _shared_with_ids.clear();
3438 /** Take a list of ranges, coalesce any that can be coalesced, then call
3439 * check_crossfades for each one.
3442 Playlist::coalesce_and_check_crossfades (list<Evoral::Range<samplepos_t> > ranges)
3444 /* XXX: it's a shame that this coalesce algorithm also exists in
3445 * TimeSelection::consolidate().
3448 /* XXX: xfade: this is implemented in Evoral::RangeList */
3451 for (list<Evoral::Range<samplepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
3452 for (list<Evoral::Range<samplepos_t> >::iterator j = ranges.begin(); j != ranges.end(); ++j) {
3458 // XXX i->from can be > i->to - is this right? coverage() will return OverlapNone in this case
3459 if (Evoral::coverage (i->from, i->to, j->from, j->to) != Evoral::OverlapNone) {
3460 i->from = min (i->from, j->from);
3461 i->to = max (i->to, j->to);
3470 Playlist::set_capture_insertion_in_progress (bool yn)
3472 _capture_insertion_underway = yn;