NO-OP: whitespace
[ardour.git] / libs / ardour / playlist.cc
1 /*
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>
12  *
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.
17  *
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.
22  *
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.
26  */
27
28 #include <stdint.h>
29 #include <set>
30 #include <algorithm>
31 #include <string>
32
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"
38
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"
53
54 #include "pbd/i18n.h"
55
56 using namespace std;
57 using namespace ARDOUR;
58 using namespace PBD;
59
60 namespace ARDOUR {
61         namespace Properties {
62                 PBD::PropertyDescriptor<bool> regions;
63         }
64 }
65
66 struct ShowMeTheList {
67         ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
68         ~ShowMeTheList () {
69                 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
70         };
71         boost::shared_ptr<Playlist> playlist;
72         string name;
73 };
74
75 void
76 Playlist::make_property_quarks ()
77 {
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));
81 }
82
83 RegionListProperty::RegionListProperty (Playlist& pl)
84         : SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
85         , _playlist (pl)
86 {
87
88 }
89
90 RegionListProperty::RegionListProperty (RegionListProperty const & p)
91         : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
92         , _playlist (p._playlist)
93 {
94
95 }
96
97 RegionListProperty *
98 RegionListProperty::clone () const
99 {
100         return new RegionListProperty (*this);
101 }
102
103 RegionListProperty *
104 RegionListProperty::create () const
105 {
106         return new RegionListProperty (_playlist);
107 }
108
109 void
110 RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
111 {
112         /* All regions (even those which are deleted) have their state
113          * saved by other code, so we can just store ID here.
114          */
115
116         node.set_property ("id", region->id());
117 }
118
119 boost::shared_ptr<Region>
120 RegionListProperty::get_content_from_xml (XMLNode const & node) const
121 {
122         PBD::ID id;
123         if (!node.get_property ("id", id)) {
124                 assert (false);
125         }
126
127         boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
128
129         if (!ret) {
130                 ret = RegionFactory::region_by_id (id);
131         }
132
133         return ret;
134 }
135
136 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
137         : SessionObject(sess, nom)
138         , regions (*this)
139         , _type(type)
140 {
141         init (hide);
142         first_set_state = false;
143         _name = nom;
144         _set_sort_id ();
145 }
146
147 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
148         : SessionObject(sess, "unnamed playlist")
149         , regions (*this)
150         , _type(type)
151 {
152 #ifndef NDEBUG
153         XMLProperty const * prop = node.property("type");
154         assert(!prop || DataType(prop->value()) == _type);
155 #endif
156
157         init (hide);
158         _name = "unnamed"; /* reset by set_state */
159         _set_sort_id ();
160
161         /* set state called by derived class */
162 }
163
164 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
165         : SessionObject(other->_session, namestr)
166         , regions (*this)
167         , _type(other->_type)
168         , _orig_track_id (other->_orig_track_id)
169         , _shared_with_ids (other->_shared_with_ids)
170 {
171         init (hide);
172
173         RegionList tmp;
174         other->copy_regions (tmp);
175
176         in_set_state++;
177
178         for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
179                 add_region_internal( (*x), (*x)->position());
180         }
181
182         in_set_state--;
183
184         _splicing  = other->_splicing;
185         _rippling  = other->_rippling;
186         _nudging   = other->_nudging;
187         _edit_mode = other->_edit_mode;
188
189         in_set_state = 0;
190         first_set_state = false;
191         in_flush = false;
192         in_partition = false;
193         subcnt = 0;
194         _frozen = other->_frozen;
195 }
196
197 Playlist::Playlist (boost::shared_ptr<const Playlist> other, samplepos_t start, samplecnt_t cnt, string str, bool hide)
198         : SessionObject(other->_session, str)
199         , regions (*this)
200         , _type(other->_type)
201         , _orig_track_id (other->_orig_track_id)
202         , _shared_with_ids (other->_shared_with_ids)
203 {
204         RegionReadLock rlock2 (const_cast<Playlist*> (other.get()));
205
206         samplepos_t end = start + cnt - 1;
207
208         init (hide);
209
210         in_set_state++;
211
212         for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
213
214                 boost::shared_ptr<Region> region;
215                 boost::shared_ptr<Region> new_region;
216                 sampleoffset_t offset = 0;
217                 samplepos_t position = 0;
218                 samplecnt_t len = 0;
219                 string    new_name;
220                 Evoral::OverlapType overlap;
221
222                 region = *i;
223
224                 overlap = region->coverage (start, end);
225
226                 switch (overlap) {
227                 case Evoral::OverlapNone:
228                         continue;
229
230                 case Evoral::OverlapInternal:
231                         offset = start - region->position();
232                         position = 0;
233                         len = cnt;
234                         break;
235
236                 case Evoral::OverlapStart:
237                         offset = 0;
238                         position = region->position() - start;
239                         len = end - region->position();
240                         break;
241
242                 case Evoral::OverlapEnd:
243                         offset = start - region->position();
244                         position = 0;
245                         len = region->length() - offset;
246                         break;
247
248                 case Evoral::OverlapExternal:
249                         offset = 0;
250                         position = region->position() - start;
251                         len = region->length();
252                         break;
253                 }
254
255                 RegionFactory::region_name (new_name, region->name(), false);
256
257                 PropertyList plist;
258
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());
264
265                 new_region = RegionFactory::create (region, plist);
266
267                 add_region_internal (new_region, position);
268         }
269
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);
273
274         in_set_state--;
275         first_set_state = false;
276 }
277
278 void
279 Playlist::use ()
280 {
281         ++_refcnt;
282         InUse (true); /* EMIT SIGNAL */
283 }
284
285 void
286 Playlist::release ()
287 {
288         if (_refcnt > 0) {
289                 _refcnt--;
290         }
291
292         if (_refcnt == 0) {
293                 InUse (false); /* EMIT SIGNAL */
294         }
295 }
296
297 void
298 Playlist::copy_regions (RegionList& newlist) const
299 {
300         RegionReadLock rlock (const_cast<Playlist *> (this));
301
302         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
303                 newlist.push_back (RegionFactory::create (*i, true, true));
304         }
305 }
306
307 void
308 Playlist::init (bool hide)
309 {
310         add_property (regions);
311         _xml_node_name = X_("Playlist");
312
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;
318         _refcnt = 0;
319         _hidden = hide;
320         _splicing = false;
321         _rippling = false;
322         _shuffling = false;
323         _nudging = false;
324         in_set_state = 0;
325         in_undo = false;
326         _edit_mode = Config->get_edit_mode();
327         in_flush = false;
328         in_partition = false;
329         subcnt = 0;
330         _frozen = false;
331         _capture_insertion_underway = false;
332         _combine_ops = 0;
333         _end_space = 0;
334         _playlist_shift_active = false;
335
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));
338
339         ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this));
340 }
341
342 Playlist::~Playlist ()
343 {
344         DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name));
345
346         {
347                 RegionReadLock rl (this);
348
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>());
351                 }
352         }
353
354         /* GoingAway must be emitted by derived classes */
355 }
356
357 void
358 Playlist::_set_sort_id ()
359 {
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.
363          */
364
365         size_t dot_position = _name.val().find_last_of(".");
366
367         if (dot_position == string::npos) {
368                 _sort_id = 0;
369         } else {
370                 string t = _name.val().substr(dot_position + 1);
371
372                 if (!string_to_uint32 (t, _sort_id)) {
373                         _sort_id = 0;
374                 }
375         }
376 }
377
378 bool
379 Playlist::set_name (const string& str)
380 {
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.
385          */
386
387         if (_refcnt > 2) {
388                 return false;
389         }
390
391         bool ret =  SessionObject::set_name(str);
392         if (ret) {
393                 _set_sort_id ();
394         }
395         return ret;
396 }
397
398 /***********************************************************************
399  * CHANGE NOTIFICATION HANDLING
400  *
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  ***********************************************************************/
405
406 void
407 Playlist::begin_undo ()
408 {
409         in_undo = true;
410         freeze ();
411 }
412
413 void
414 Playlist::end_undo ()
415 {
416         thaw (true);
417         in_undo = false;
418 }
419
420 void
421 Playlist::freeze ()
422 {
423         delay_notifications ();
424         g_atomic_int_inc (&ignore_state_changes);
425 }
426
427 /** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
428 void
429 Playlist::thaw (bool from_undo)
430 {
431         g_atomic_int_dec_and_test (&ignore_state_changes);
432         release_notifications (from_undo);
433 }
434
435
436 void
437 Playlist::delay_notifications ()
438 {
439         g_atomic_int_inc (&block_notifications);
440 }
441
442 /** @param from_undo true if this release is triggered by the end of an undo on this playlist */
443 void
444 Playlist::release_notifications (bool from_undo)
445 {
446         if (g_atomic_int_dec_and_test (&block_notifications)) {
447                 flush_notifications (from_undo);
448         }
449 }
450
451 void
452 Playlist::notify_contents_changed ()
453 {
454         if (holding_state ()) {
455                 pending_contents_change = true;
456         } else {
457                 pending_contents_change = false;
458                 ContentsChanged(); /* EMIT SIGNAL */
459         }
460 }
461
462 void
463 Playlist::notify_layering_changed ()
464 {
465         if (holding_state ()) {
466                 pending_layering = true;
467         } else {
468                 pending_layering = false;
469                 LayeringChanged(); /* EMIT SIGNAL */
470         }
471 }
472
473 void
474 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
475 {
476         if (holding_state ()) {
477                 pending_removes.insert (r);
478                 pending_contents_change = true;
479         } else {
480                 /* this might not be true, but we have to act
481                    as though it could be.
482                 */
483                 pending_contents_change = false;
484                 RegionRemoved (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
485                 ContentsChanged (); /* EMIT SIGNAL */
486         }
487 }
488
489 void
490 Playlist::notify_region_moved (boost::shared_ptr<Region> r)
491 {
492         Evoral::RangeMove<samplepos_t> const move (r->last_position (), r->length (), r->position ());
493
494         if (holding_state ()) {
495
496                 pending_range_moves.push_back (move);
497
498         } else {
499
500                 list< Evoral::RangeMove<samplepos_t> > m;
501                 m.push_back (move);
502                 RangesMoved (m, false);
503         }
504
505 }
506
507 void
508 Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r)
509 {
510         if (r->position() >= r->last_position()) {
511                 /* trimmed shorter */
512                 return;
513         }
514
515         Evoral::Range<samplepos_t> const extra (r->position(), r->last_position());
516
517         if (holding_state ()) {
518
519                 pending_region_extensions.push_back (extra);
520
521         } else {
522
523                 list<Evoral::Range<samplepos_t> > r;
524                 r.push_back (extra);
525                 RegionsExtended (r);
526
527         }
528 }
529
530 void
531 Playlist::notify_region_end_trimmed (boost::shared_ptr<Region> r)
532 {
533         if (r->length() < r->last_length()) {
534                 /* trimmed shorter */
535         }
536
537         Evoral::Range<samplepos_t> const extra (r->position() + r->last_length(), r->position() + r->length());
538
539         if (holding_state ()) {
540
541                 pending_region_extensions.push_back (extra);
542
543         } else {
544
545                 list<Evoral::Range<samplepos_t> > r;
546                 r.push_back (extra);
547                 RegionsExtended (r);
548         }
549 }
550
551
552 void
553 Playlist::notify_region_added (boost::shared_ptr<Region> r)
554 {
555         /* the length change might not be true, but we have to act
556          * as though it could be.
557          */
558
559         if (holding_state()) {
560                 pending_adds.insert (r);
561                 pending_contents_change = true;
562         } else {
563                 r->clear_changes ();
564                 pending_contents_change = false;
565                 RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
566                 ContentsChanged (); /* EMIT SIGNAL */
567
568         }
569 }
570
571 /** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
572 void
573 Playlist::flush_notifications (bool from_undo)
574 {
575         set<boost::shared_ptr<Region> >::iterator s;
576         bool regions_changed = false;
577
578         if (in_flush) {
579                 return;
580         }
581
582         in_flush = true;
583
584         if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
585                 regions_changed = true;
586         }
587
588         /* XXX: it'd be nice if we could use pending_bounds for
589            RegionsExtended and RegionsMoved.
590         */
591
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.
596          */
597
598         // RegionSortByLayer cmp;
599         // pending_bounds.sort (cmp);
600
601         list<Evoral::Range<samplepos_t> > crossfade_ranges;
602
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 ());
606         }
607
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);
613         }
614
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
620                 */
621         }
622
623         /* notify about contents/region changes first so that layering changes
624          * in a UI will take place on the new contents.
625          */
626
627         if (regions_changed || pending_contents_change) {
628                 pending_layering = true;
629                 ContentsChanged (); /* EMIT SIGNAL */
630         }
631
632         for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
633                 (*s)->clear_changes ();
634                 RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
635         }
636
637         if ((regions_changed && !in_set_state) || pending_layering) {
638                 relayer ();
639         }
640
641         coalesce_and_check_crossfades (crossfade_ranges);
642
643         if (!pending_range_moves.empty ()) {
644                 /* We don't need to check crossfades for these as pending_bounds has
645                    already covered it.
646                 */
647                 RangesMoved (pending_range_moves, from_undo || _playlist_shift_active);
648         }
649
650         if (!pending_region_extensions.empty ()) {
651                 RegionsExtended (pending_region_extensions);
652         }
653
654         clear_pending ();
655
656         in_flush = false;
657 }
658
659 void
660 Playlist::clear_pending ()
661 {
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;
669 }
670
671 /*************************************************************
672  * PLAYLIST OPERATIONS
673  *************************************************************/
674
675 /** Note: this calls set_layer (..., DBL_MAX) so it will reset the layering index of region */
676 void
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)
678 {
679         RegionWriteLock rlock (this);
680         times = fabs (times);
681
682         int itimes = (int) floor (times);
683
684         samplepos_t pos = position;
685
686         if (times == 1 && auto_partition){
687                 RegionList thawlist;
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));
692                 }
693         }
694
695         if (itimes >= 1) {
696                 add_region_internal (region, pos, sub_num, quarter_note, for_music);
697                 set_layer (region, DBL_MAX);
698                 pos += region->length();
699                 --itimes;
700         }
701
702         /* note that itimes can be zero if we being asked to just
703          * insert a single fraction of the region.
704          */
705
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();
711         }
712
713         samplecnt_t length = 0;
714
715         if (floor (times) != times) {
716                 length = (samplecnt_t) floor (region->length() * (times - floor (times)));
717                 string name;
718                 RegionFactory::region_name (name, region->name(), false);
719
720                 {
721                         PropertyList plist;
722
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());
727
728                         boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
729                         add_region_internal (sub, pos, sub_num);
730                         set_layer (sub, DBL_MAX);
731                 }
732         }
733
734         possibly_splice_unlocked (position, (pos + length) - position, region);
735 }
736
737 void
738 Playlist::set_region_ownership ()
739 {
740         RegionWriteLock rl (this);
741         RegionList::iterator i;
742         boost::weak_ptr<Playlist> pl (shared_from_this());
743
744         for (i = regions.begin(); i != regions.end(); ++i) {
745                 (*i)->set_playlist (pl);
746         }
747 }
748
749 bool
750 Playlist::add_region_internal (boost::shared_ptr<Region> region, samplepos_t position, int32_t sub_num, double quarter_note, bool for_music)
751 {
752         if (region->data_type() != _type) {
753                 return false;
754         }
755
756         RegionSortByPosition cmp;
757
758         if (!first_set_state) {
759                 boost::shared_ptr<Playlist> foo (shared_from_this());
760                 region->set_playlist (boost::weak_ptr<Playlist>(foo));
761         }
762         if (for_music) {
763                 region->set_position_music (quarter_note);
764         } else {
765                 region->set_position (position, sub_num);
766         }
767
768         regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
769         all_regions.insert (region);
770
771         possibly_splice_unlocked (position, region->length(), region);
772
773         if (!holding_state ()) {
774                 /* layers get assigned from XML state, and are not reset during undo/redo */
775                 relayer ();
776         }
777
778         /* we need to notify the existence of new region before checking dependents. Ick. */
779
780         notify_region_added (region);
781
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)));
784
785         return true;
786 }
787
788 void
789 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, samplepos_t pos)
790 {
791         RegionWriteLock rlock (this);
792
793         bool old_sp = _splicing;
794         _splicing = true;
795
796         remove_region_internal (old);
797         add_region_internal (newr, pos);
798         set_layer (newr, old->layer ());
799
800         _splicing = old_sp;
801
802         possibly_splice_unlocked (pos, old->length() - newr->length());
803 }
804
805 void
806 Playlist::remove_region (boost::shared_ptr<Region> region)
807 {
808         RegionWriteLock rlock (this);
809         remove_region_internal (region);
810 }
811
812 int
813 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
814 {
815         RegionList::iterator i;
816
817         if (!in_set_state) {
818                 /* unset playlist */
819                 region->set_playlist (boost::weak_ptr<Playlist>());
820         }
821
822         /* XXX should probably freeze here .... */
823
824         for (i = regions.begin(); i != regions.end(); ++i) {
825                 if (*i == region) {
826
827                         samplepos_t pos = (*i)->position();
828                         samplecnt_t distance = (*i)->length();
829
830                         regions.erase (i);
831
832                         possibly_splice_unlocked (pos, -distance);
833
834                         if (!holding_state ()) {
835                                 relayer ();
836                                 remove_dependents (region);
837                         }
838
839                         notify_region_removed (region);
840                         break;
841                 }
842         }
843
844         return -1;
845 }
846
847 void
848 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
849 {
850         switch (Config->get_region_equivalence()) {
851                  case Exact:
852                          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
853                                  if ((*i)->exact_equivalent (other)) {
854                                          results.push_back (*i);
855                                  }
856                          }
857                          break;
858                  case LayerTime:
859                          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
860                                  if ((*i)->layer_and_time_equivalent (other)) {
861                                          results.push_back (*i);
862                                  }
863                          }
864                          break;
865                  case Enclosed:
866                          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
867                                  if ((*i)->enclosed_equivalent (other)) {
868                                          results.push_back (*i);
869                                  }
870                          }
871                          break;
872                  case Overlap:
873                          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
874                                  if ((*i)->overlap_equivalent (other)) {
875                                          results.push_back (*i);
876                                  }
877                          }
878                          break;
879         }
880 }
881
882 void
883 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
884 {
885         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
886
887                 if ((*i) && (*i)->region_list_equivalent (other)) {
888                         results.push_back (*i);
889                 }
890         }
891 }
892
893 void
894 Playlist::get_source_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
895 {
896         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
897
898                 if ((*i) && (*i)->any_source_equivalent (other)) {
899                         results.push_back (*i);
900                 }
901         }
902 }
903
904 void
905 Playlist::partition (samplepos_t start, samplepos_t end, bool cut)
906 {
907         RegionList thawlist;
908         {
909                 RegionWriteLock lock(this);
910                 partition_internal (start, end, cut, thawlist);
911         }
912
913         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
914                 (*i)->resume_property_changes ();
915         }
916 }
917
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()
921  */
922 static void maybe_add_start_beats (TempoMap const& tm, PropertyList& plist, boost::shared_ptr<Region> r, samplepos_t start, samplepos_t end)
923 {
924         boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(r);
925         if (!mr) {
926                 return;
927         }
928         double delta_beats = tm.quarter_notes_between_samples (start, end);
929         plist.add (Properties::start_beats, mr->start_beats () + delta_beats);
930 }
931
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
934  *  removed.
935  */
936 void
937 Playlist::partition_internal (samplepos_t start, samplepos_t end, bool cutting, RegionList& thawlist)
938 {
939         RegionList new_regions;
940
941         {
942
943                 boost::shared_ptr<Region> region;
944                 boost::shared_ptr<Region> current;
945                 string new_name;
946                 RegionList::iterator tmp;
947                 Evoral::OverlapType overlap;
948                 samplepos_t pos1, pos2, pos3, pos4;
949
950                 in_partition = true;
951
952                 /* need to work from a copy, because otherwise the regions we add
953                  * during the process get operated on as well.
954                  */
955
956                 RegionList copy = regions.rlist();
957
958                 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
959
960                         tmp = i;
961                         ++tmp;
962
963                         current = *i;
964
965                         if (current->first_sample() >= start && current->last_sample() < end) {
966
967                                 if (cutting) {
968                                         remove_region_internal (current);
969                                 }
970
971                                 continue;
972                         }
973
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.
977                          */
978
979                         if (current->first_sample() >= end) {
980                                 continue;
981                         }
982
983                         if ((overlap = current->coverage (start, end)) == Evoral::OverlapNone) {
984                                 continue;
985                         }
986
987                         pos1 = current->position();
988                         pos2 = start;
989                         pos3 = end;
990                         pos4 = current->last_sample();
991
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.
995                                  *
996                                  *
997                                  * start                 end
998                                  * ---------------*************************------------
999                                  * P1  P2              P3  P4
1000                                  * SPLIT:
1001                                  * ---------------*****++++++++++++++++====------------
1002                                  * CUT
1003                                  * ---------------*****----------------====------------
1004                                  */
1005
1006                                 if (!cutting) {
1007                                         /* "middle" ++++++ */
1008
1009                                         RegionFactory::region_name (new_name, current->name(), false);
1010
1011                                         PropertyList plist;
1012
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));
1022
1023                                         /* see note in :_split_region()
1024                                          * for MusicSample is needed to offset region-gain
1025                                          */
1026                                         region = RegionFactory::create (current, MusicSample (pos2 - pos1, 0), plist);
1027                                         add_region_internal (region, start);
1028                                         new_regions.push_back (region);
1029                                 }
1030
1031                                 /* "end" ====== */
1032
1033                                 RegionFactory::region_name (new_name, current->name(), false);
1034
1035                                 PropertyList plist;
1036
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));
1045
1046                                 region = RegionFactory::create (current, MusicSample (pos3 - pos1, 0), plist);
1047
1048                                 add_region_internal (region, end);
1049                                 new_regions.push_back (region);
1050
1051                                 /* "front" ***** */
1052
1053                                 current->clear_changes ();
1054                                 current->suspend_property_changes ();
1055                                 thawlist.push_back (current);
1056                                 current->cut_end (pos2 - 1);
1057
1058                         } else if (overlap == Evoral::OverlapEnd) {
1059
1060                                 /*
1061                                   start           end
1062                                   ---------------*************************------------
1063                                   P1           P2         P4   P3
1064                                   SPLIT:
1065                                   ---------------**************+++++++++++------------
1066                                   CUT:
1067                                   ---------------**************-----------------------
1068                                 */
1069
1070                                 if (!cutting) {
1071
1072                                         /* end +++++ */
1073
1074                                         RegionFactory::region_name (new_name, current->name(), false);
1075
1076                                         PropertyList plist;
1077
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));
1086
1087                                         region = RegionFactory::create (current, MusicSample(pos2 - pos1, 0), plist);
1088
1089                                         add_region_internal (region, start);
1090                                         new_regions.push_back (region);
1091                                 }
1092
1093                                 /* front ****** */
1094
1095                                 current->clear_changes ();
1096                                 current->suspend_property_changes ();
1097                                 thawlist.push_back (current);
1098                                 current->cut_end (pos2 - 1);
1099
1100                         } else if (overlap == Evoral::OverlapStart) {
1101
1102                                 /* split: we need 2 regions: the front and the end.
1103                                  * cut: just trim current to skip the cut area
1104                                  *
1105                                  *
1106                                  * start           end
1107                                  * ---------------*************************------------
1108                                  * P2          P1 P3                   P4
1109                                  *
1110                                  * SPLIT:
1111                                  * ---------------****+++++++++++++++++++++------------
1112                                  * CUT:
1113                                  * -------------------*********************------------
1114                                  */
1115
1116                                 if (!cutting) {
1117                                         /* front **** */
1118                                         RegionFactory::region_name (new_name, current->name(), false);
1119
1120                                         PropertyList plist;
1121
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());
1130
1131                                         region = RegionFactory::create (current, plist);
1132
1133                                         add_region_internal (region, pos1);
1134                                         new_regions.push_back (region);
1135                                 }
1136
1137                                 /* end */
1138
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) {
1144
1145                                 /* split: no split required.
1146                                  * cut: remove the region.
1147                                  *
1148                                  *
1149                                  * start                                      end
1150                                  * ---------------*************************------------
1151                                  * P2          P1 P3                   P4
1152                                  *
1153                                  *
1154                                  * SPLIT:
1155                                  * ---------------*************************------------
1156                                  * CUT:
1157                                  * ----------------------------------------------------
1158                                  *
1159                                  */
1160
1161                                 if (cutting) {
1162                                         remove_region_internal (current);
1163                                 }
1164
1165                                 new_regions.push_back (current);
1166                         }
1167                 }
1168
1169                 in_partition = false;
1170         }
1171
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;
1175 }
1176
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)
1179 {
1180         boost::shared_ptr<Playlist> ret;
1181         boost::shared_ptr<Playlist> pl;
1182         samplepos_t start;
1183
1184         if (ranges.empty()) {
1185                 return boost::shared_ptr<Playlist>();
1186         }
1187
1188         start = ranges.front().start;
1189
1190         for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1191
1192                 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1193
1194                 if (i == ranges.begin()) {
1195                         ret = pl;
1196                 } else {
1197
1198                         /* paste the next section into the nascent playlist,
1199                          * offset to reflect the start of the first range we
1200                          * chopped.
1201                          */
1202
1203                         ret->paste (pl, (*i).start - start, 1.0f, 0);
1204                 }
1205         }
1206
1207         return ret;
1208 }
1209
1210 boost::shared_ptr<Playlist>
1211 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1212 {
1213         boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t,samplecnt_t,bool) = &Playlist::cut;
1214         return cut_copy (pmf, ranges, result_is_hidden);
1215 }
1216
1217 boost::shared_ptr<Playlist>
1218 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1219 {
1220         boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t,samplecnt_t,bool) = &Playlist::copy;
1221         return cut_copy (pmf, ranges, result_is_hidden);
1222 }
1223
1224 boost::shared_ptr<Playlist>
1225 Playlist::cut (samplepos_t start, samplecnt_t cnt, bool result_is_hidden)
1226 {
1227         boost::shared_ptr<Playlist> the_copy;
1228         RegionList thawlist;
1229         char buf[32];
1230
1231         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1232         string new_name = _name;
1233         new_name += '.';
1234         new_name += buf;
1235
1236         if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1237                 return boost::shared_ptr<Playlist>();
1238         }
1239
1240         {
1241                 RegionWriteLock rlock (this);
1242                 partition_internal (start, start+cnt-1, true, thawlist);
1243         }
1244
1245         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1246                 (*i)->resume_property_changes();
1247         }
1248
1249         return the_copy;
1250 }
1251
1252 boost::shared_ptr<Playlist>
1253 Playlist::copy (samplepos_t start, samplecnt_t cnt, bool result_is_hidden)
1254 {
1255         char buf[32];
1256
1257         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1258         string new_name = _name;
1259         new_name += '.';
1260         new_name += buf;
1261
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... )
1263
1264         return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1265 }
1266
1267 int
1268 Playlist::paste (boost::shared_ptr<Playlist> other, samplepos_t position, float times, const int32_t sub_num)
1269 {
1270         times = fabs (times);
1271
1272         {
1273                 RegionReadLock rl2 (other.get());
1274
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 ();
1279
1280                 {
1281                         RegionWriteLock rl1 (this);
1282                         while (itimes--) {
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);
1285
1286                                         /* put these new regions on top of all existing ones, but preserve
1287                                            the ordering they had in the original playlist.
1288                                         */
1289
1290                                         add_region_internal (copy_of_region, (*i)->position() + pos, sub_num);
1291                                         set_layer (copy_of_region, copy_of_region->layer() + top);
1292                                 }
1293                                 pos += shift;
1294                         }
1295                 }
1296         }
1297
1298         return 0;
1299 }
1300
1301
1302 void
1303 Playlist::duplicate (boost::shared_ptr<Region> region, samplepos_t position, float times)
1304 {
1305         duplicate(region, position, region->length(), times);
1306 }
1307
1308 /** @param gap from the beginning of the region to the next beginning */
1309 void
1310 Playlist::duplicate (boost::shared_ptr<Region> region, samplepos_t position, samplecnt_t gap, float times)
1311 {
1312         times = fabs (times);
1313
1314         RegionWriteLock rl (this);
1315         int itimes = (int) floor (times);
1316
1317         while (itimes--) {
1318                 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1319                 add_region_internal (copy, position);
1320                 set_layer (copy, DBL_MAX);
1321                 position += gap;
1322         }
1323
1324         if (floor (times) != times) {
1325                 samplecnt_t length = (samplecnt_t) floor (region->length() * (times - floor (times)));
1326                 string name;
1327                 RegionFactory::region_name (name, region->name(), false);
1328
1329                 {
1330                         PropertyList plist;
1331
1332                         plist.add (Properties::start, region->start());
1333                         plist.add (Properties::length, length);
1334                         plist.add (Properties::name, name);
1335
1336                         boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1337                         add_region_internal (sub, position);
1338                         set_layer (sub, DBL_MAX);
1339                 }
1340         }
1341 }
1342
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 */
1345 void
1346 Playlist::duplicate_until (boost::shared_ptr<Region> region, samplepos_t position, samplecnt_t gap, samplepos_t end)
1347 {
1348          RegionWriteLock rl (this);
1349
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);
1354                  position += gap;
1355          }
1356
1357          if (position < end) {
1358                  samplecnt_t length = min (region->length(), end - position);
1359                  string name;
1360                  RegionFactory::region_name (name, region->name(), false);
1361
1362                  {
1363                          PropertyList plist;
1364
1365                          plist.add (Properties::start, region->start());
1366                          plist.add (Properties::length, length);
1367                          plist.add (Properties::name, name);
1368
1369                          boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1370                          add_region_internal (sub, position);
1371                          set_layer (sub, DBL_MAX);
1372                  }
1373          }
1374 }
1375
1376 void
1377 Playlist::duplicate_range (AudioRange& range, float times)
1378 {
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);
1382 }
1383
1384 void
1385 Playlist::duplicate_ranges (std::list<AudioRange>& ranges, float times)
1386 {
1387         if (ranges.empty()) {
1388                 return;
1389         }
1390
1391         samplepos_t min_pos = max_samplepos;
1392         samplepos_t max_pos = 0;
1393
1394         for (std::list<AudioRange>::const_iterator i = ranges.begin();
1395              i != ranges.end();
1396              ++i) {
1397                 min_pos = min (min_pos, (*i).start);
1398                 max_pos = max (max_pos, (*i).end);
1399         }
1400
1401         samplecnt_t offset = max_pos - min_pos;
1402
1403         int count = 1;
1404         int itimes = (int) floor (times);
1405         while (itimes--) {
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);
1409                 }
1410                 ++count;
1411         }
1412 }
1413
1414 void
1415 Playlist::shift (samplepos_t at, sampleoffset_t distance, bool move_intersected, bool ignore_music_glue)
1416 {
1417         PBD::Unwinder<bool> uw (_playlist_shift_active, true);
1418         RegionWriteLock rlock (this);
1419         RegionList copy (regions.rlist());
1420         RegionList fixup;
1421
1422         for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1423
1424                 if ((*r)->last_sample() < at) {
1425                         /* too early */
1426                         continue;
1427                 }
1428
1429                 if (at > (*r)->first_sample() && at < (*r)->last_sample()) {
1430                         /* intersected region */
1431                         if (!move_intersected) {
1432                                 continue;
1433                         }
1434                 }
1435
1436                 /* do not move regions glued to music time - that
1437                  * has to be done separately.
1438                  */
1439
1440                 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1441                         fixup.push_back (*r);
1442                         continue;
1443                 }
1444
1445                 (*r)->set_position ((*r)->position() + distance);
1446         }
1447
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);
1451         }
1452 }
1453
1454 void
1455 Playlist::split (const MusicSample& at)
1456 {
1457         RegionWriteLock rlock (this);
1458         RegionList copy (regions.rlist());
1459
1460         /* use a copy since this operation can modify the region list */
1461
1462         for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1463                 _split_region (*r, at);
1464         }
1465 }
1466
1467 void
1468 Playlist::split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position)
1469 {
1470         RegionWriteLock rl (this);
1471         _split_region (region, playlist_position);
1472 }
1473
1474 void
1475 Playlist::_split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position)
1476 {
1477         if (!region->covers (playlist_position.sample)) {
1478                 return;
1479         }
1480
1481         if (region->position() == playlist_position.sample ||
1482                         region->last_sample() == playlist_position.sample) {
1483                 return;
1484         }
1485
1486         boost::shared_ptr<Region> left;
1487         boost::shared_ptr<Region> right;
1488
1489         MusicSample before (playlist_position.sample - region->position(), playlist_position.division);
1490         MusicSample after (region->length() - before.sample, 0);
1491         string before_name;
1492         string after_name;
1493
1494         /* split doesn't change anything about length, so don't try to splice */
1495
1496         bool old_sp = _splicing;
1497         _splicing = true;
1498
1499         RegionFactory::region_name (before_name, region->name(), false);
1500
1501         {
1502                 PropertyList plist;
1503
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 ());
1509
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.
1513                  */
1514                 left = RegionFactory::create (region, MusicSample (0, 0), plist, true);
1515         }
1516
1517         RegionFactory::region_name (after_name, region->name(), false);
1518
1519         {
1520                 PropertyList plist;
1521
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 ());
1527
1528                 /* same note as above */
1529                 right = RegionFactory::create (region, before, plist, true);
1530         }
1531
1532         add_region_internal (left, region->position(), 0);
1533         add_region_internal (right, region->position() + before.sample, before.division);
1534
1535         remove_region_internal (region);
1536
1537         _splicing = old_sp;
1538 }
1539
1540 void
1541 Playlist::AddToSoloSelectedList(const Region* r)
1542 {
1543         _soloSelectedRegions.insert (r);
1544 }
1545
1546
1547 void
1548 Playlist::RemoveFromSoloSelectedList(const Region* r)
1549 {
1550         _soloSelectedRegions.erase (r);
1551 }
1552
1553
1554 bool
1555 Playlist::SoloSelectedListIncludes(const Region* r)
1556 {
1557         std::set<const Region*>::iterator i = _soloSelectedRegions.find(r);
1558
1559         return ( i != _soloSelectedRegions.end() );
1560 }
1561
1562 bool
1563 Playlist::SoloSelectedActive()
1564 {
1565         return !_soloSelectedRegions.empty();
1566 }
1567
1568
1569 void
1570 Playlist::possibly_splice (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1571 {
1572         if (_splicing || in_set_state) {
1573                 /* don't respond to splicing moves or state setting */
1574                 return;
1575         }
1576
1577         if (_edit_mode == Splice) {
1578                 splice_locked (at, distance, exclude);
1579         }
1580 }
1581
1582 void
1583 Playlist::possibly_splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1584 {
1585         if (_splicing || in_set_state) {
1586                 /* don't respond to splicing moves or state setting */
1587                 return;
1588         }
1589
1590         if (_edit_mode == Splice) {
1591                 splice_unlocked (at, distance, exclude);
1592         }
1593 }
1594
1595 void
1596 Playlist::splice_locked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1597 {
1598         {
1599                 RegionWriteLock rl (this);
1600                 core_splice (at, distance, exclude);
1601         }
1602 }
1603
1604 void
1605 Playlist::splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1606 {
1607         core_splice (at, distance, exclude);
1608 }
1609
1610 void
1611 Playlist::core_splice (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1612 {
1613         _splicing = true;
1614
1615         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1616
1617                 if (exclude && (*i) == exclude) {
1618                         continue;
1619                 }
1620
1621                 if ((*i)->position() >= at) {
1622                         samplepos_t new_pos = (*i)->position() + distance;
1623                         if (new_pos < 0) {
1624                                 new_pos = 0;
1625                         } else if (new_pos >= max_samplepos - (*i)->length()) {
1626                                 new_pos = max_samplepos - (*i)->length();
1627                         }
1628
1629                         (*i)->set_position (new_pos);
1630                 }
1631         }
1632
1633         _splicing = false;
1634
1635         notify_contents_changed ();
1636 }
1637
1638 void
1639 Playlist::ripple_locked (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1640 {
1641         {
1642                 RegionWriteLock rl (this);
1643                 core_ripple (at, distance, exclude);
1644         }
1645 }
1646
1647 void
1648 Playlist::ripple_unlocked (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1649 {
1650         core_ripple (at, distance, exclude);
1651 }
1652
1653 void
1654 Playlist::core_ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1655 {
1656         if (distance == 0) {
1657                 return;
1658         }
1659
1660         _rippling = true;
1661         RegionListProperty copy = regions;
1662         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1663                 assert (i != copy.end());
1664
1665                 if (exclude) {
1666                         if (std::find(exclude->begin(), exclude->end(), (*i)) != exclude->end()) {
1667                                 continue;
1668                         }
1669                 }
1670
1671                 if ((*i)->position() >= at) {
1672                         samplepos_t new_pos = (*i)->position() + distance;
1673                         samplepos_t limit = max_samplepos - (*i)->length();
1674                         if (new_pos < 0) {
1675                                 new_pos = 0;
1676                         } else if (new_pos >= limit ) {
1677                                 new_pos = limit;
1678                         }
1679
1680                         (*i)->set_position (new_pos);
1681                 }
1682         }
1683
1684         _rippling = false;
1685         notify_contents_changed ();
1686 }
1687
1688
1689 void
1690 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1691 {
1692         if (in_set_state || _splicing || _rippling || _nudging || _shuffling) {
1693                 return;
1694         }
1695
1696         if (what_changed.contains (Properties::position)) {
1697
1698                 /* remove it from the list then add it back in
1699                  * the right place again.
1700                  */
1701
1702                 RegionSortByPosition cmp;
1703
1704                 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1705
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
1709                          * it is added
1710                          */
1711                         return;
1712                 }
1713
1714                 regions.erase (i);
1715                 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1716         }
1717
1718         if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1719
1720                 sampleoffset_t delta = 0;
1721
1722                 if (what_changed.contains (Properties::position)) {
1723                         delta = region->position() - region->last_position();
1724                 }
1725
1726                 if (what_changed.contains (Properties::length)) {
1727                         delta += region->length() - region->last_length();
1728                 }
1729
1730                 if (delta) {
1731                         possibly_splice (region->last_position() + region->last_length(), delta, region);
1732                 }
1733
1734                 if (holding_state ()) {
1735                         pending_bounds.push_back (region);
1736                 } else {
1737                         notify_contents_changed ();
1738                         relayer ();
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);
1743                 }
1744         }
1745 }
1746
1747 void
1748 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1749 {
1750         boost::shared_ptr<Region> region (weak_region.lock());
1751
1752         if (!region) {
1753                 return;
1754         }
1755
1756         /* this makes a virtual call to the right kind of playlist ... */
1757
1758         region_changed (what_changed, region);
1759 }
1760
1761 bool
1762 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1763 {
1764         PropertyChange our_interests;
1765         PropertyChange bounds;
1766         bool save = false;
1767
1768         if (in_set_state || in_flush) {
1769                 return false;
1770         }
1771
1772         our_interests.add (Properties::muted);
1773         our_interests.add (Properties::layer);
1774         our_interests.add (Properties::opaque);
1775         our_interests.add (Properties::contents);
1776
1777         bounds.add (Properties::start);
1778         bounds.add (Properties::position);
1779         bounds.add (Properties::length);
1780
1781         bool send_contents = false;
1782
1783         if (what_changed.contains (bounds)) {
1784                 region_bounds_changed (what_changed, region);
1785                 save = !(_splicing || _nudging);
1786                 send_contents = true;
1787         }
1788
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);
1795         }
1796
1797         /* don't notify about layer changes, since we are the only object that can initiate
1798          * them, and we notify in ::relayer()
1799          */
1800
1801         if (what_changed.contains (our_interests)) {
1802                 save = true;
1803         }
1804
1805         if (send_contents || save) {
1806                 notify_contents_changed ();
1807         }
1808
1809         mark_session_dirty ();
1810
1811         return save;
1812 }
1813
1814 void
1815 Playlist::drop_regions ()
1816 {
1817         RegionWriteLock rl (this);
1818         regions.clear ();
1819         all_regions.clear ();
1820 }
1821
1822 void
1823 Playlist::sync_all_regions_with_regions ()
1824 {
1825         RegionWriteLock rl (this);
1826
1827         all_regions.clear ();
1828
1829         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1830                 all_regions.insert (*i);
1831         }
1832 }
1833
1834 void
1835 Playlist::clear (bool with_signals)
1836 {
1837         {
1838                 RegionWriteLock rl (this);
1839
1840                 region_state_changed_connections.drop_connections ();
1841                 region_drop_references_connections.drop_connections ();
1842
1843                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1844                         pending_removes.insert (*i);
1845                 }
1846
1847                 regions.clear ();
1848
1849                 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1850                         remove_dependents (*s);
1851                 }
1852         }
1853
1854         if (with_signals) {
1855
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 */
1858                 }
1859
1860                 pending_removes.clear ();
1861                 pending_contents_change = false;
1862                 ContentsChanged ();
1863         }
1864
1865 }
1866
1867 /* *********************************************************************
1868 FINDING THINGS
1869 **********************************************************************/
1870
1871 boost::shared_ptr<RegionList>
1872 Playlist::region_list()
1873 {
1874         RegionReadLock rlock (this);
1875         boost::shared_ptr<RegionList> rlist (new RegionList (regions.rlist ()));
1876         return rlist;
1877 }
1878
1879 void
1880 Playlist::deep_sources (std::set<boost::shared_ptr<Source> >& sources) const
1881 {
1882         RegionReadLock rlock (const_cast<Playlist*>(this));
1883
1884         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1885                 (*i)->deep_sources (sources);
1886         }
1887 }
1888
1889 boost::shared_ptr<RegionList>
1890 Playlist::regions_at (samplepos_t sample)
1891 {
1892         RegionReadLock rlock (this);
1893         return find_regions_at (sample);
1894 }
1895
1896 uint32_t
1897 Playlist::count_regions_at (samplepos_t sample) const
1898 {
1899         RegionReadLock rlock (const_cast<Playlist*>(this));
1900         uint32_t cnt = 0;
1901
1902         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1903                 if ((*i)->covers (sample)) {
1904                         cnt++;
1905                 }
1906         }
1907
1908         return cnt;
1909 }
1910
1911 boost::shared_ptr<Region>
1912 Playlist::top_region_at (samplepos_t sample)
1913 {
1914         RegionReadLock rlock (this);
1915         boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1916         boost::shared_ptr<Region> region;
1917
1918         if (rlist->size()) {
1919                 RegionSortByLayer cmp;
1920                 rlist->sort (cmp);
1921                 region = rlist->back();
1922         }
1923
1924         return region;
1925 }
1926
1927 boost::shared_ptr<Region>
1928 Playlist::top_unmuted_region_at (samplepos_t sample)
1929 {
1930         RegionReadLock rlock (this);
1931         boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1932
1933         for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1934
1935                 RegionList::iterator tmp = i;
1936
1937                 ++tmp;
1938
1939                 if ((*i)->muted()) {
1940                         rlist->erase (i);
1941                 }
1942
1943                 i = tmp;
1944         }
1945
1946         boost::shared_ptr<Region> region;
1947
1948         if (rlist->size()) {
1949                 RegionSortByLayer cmp;
1950                 rlist->sort (cmp);
1951                 region = rlist->back();
1952         }
1953
1954         return region;
1955 }
1956
1957 boost::shared_ptr<RegionList>
1958 Playlist::find_regions_at (samplepos_t sample)
1959 {
1960         /* Caller must hold lock */
1961
1962         boost::shared_ptr<RegionList> rlist (new RegionList);
1963
1964         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1965                 if ((*i)->covers (sample)) {
1966                         rlist->push_back (*i);
1967                 }
1968         }
1969
1970         return rlist;
1971 }
1972
1973 boost::shared_ptr<RegionList>
1974 Playlist::regions_with_start_within (Evoral::Range<samplepos_t> range)
1975 {
1976         RegionReadLock rlock (this);
1977         boost::shared_ptr<RegionList> rlist (new RegionList);
1978
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);
1982                 }
1983         }
1984
1985         return rlist;
1986 }
1987
1988 boost::shared_ptr<RegionList>
1989 Playlist::regions_with_end_within (Evoral::Range<samplepos_t> range)
1990 {
1991         RegionReadLock rlock (this);
1992         boost::shared_ptr<RegionList> rlist (new RegionList);
1993
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);
1997                 }
1998         }
1999
2000         return rlist;
2001 }
2002
2003 boost::shared_ptr<RegionList>
2004 Playlist::regions_touched (samplepos_t start, samplepos_t end)
2005 {
2006         RegionReadLock rlock (this);
2007         return regions_touched_locked (start, end);
2008 }
2009
2010 boost::shared_ptr<RegionList>
2011 Playlist::regions_touched_locked (samplepos_t start, samplepos_t end)
2012 {
2013         boost::shared_ptr<RegionList> rlist (new RegionList);
2014
2015         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2016                 if ((*i)->coverage (start, end) != Evoral::OverlapNone) {
2017                         rlist->push_back (*i);
2018                 }
2019         }
2020
2021         return rlist;
2022 }
2023
2024 samplepos_t
2025 Playlist::find_next_transient (samplepos_t from, int dir)
2026 {
2027         RegionReadLock rlock (this);
2028         AnalysisFeatureList points;
2029         AnalysisFeatureList these_points;
2030
2031         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2032                 if (dir > 0) {
2033                         if ((*i)->last_sample() < from) {
2034                                 continue;
2035                         }
2036                 } else {
2037                         if ((*i)->first_sample() > from) {
2038                                 continue;
2039                         }
2040                 }
2041
2042                 (*i)->get_transients (these_points);
2043
2044                 /* add first sample, just, err, because */
2045
2046                 these_points.push_back ((*i)->first_sample());
2047
2048                 points.insert (points.end(), these_points.begin(), these_points.end());
2049                 these_points.clear ();
2050         }
2051
2052         if (points.empty()) {
2053                 return -1;
2054         }
2055
2056         TransientDetector::cleanup_transients (points, _session.sample_rate(), 3.0);
2057         bool reached = false;
2058
2059         if (dir > 0) {
2060                 for (AnalysisFeatureList::const_iterator x = points.begin(); x != points.end(); ++x) {
2061                         if ((*x) >= from) {
2062                                 reached = true;
2063                         }
2064
2065                         if (reached && (*x) > from) {
2066                                 return *x;
2067                         }
2068                 }
2069         } else {
2070                 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2071                         if ((*x) <= from) {
2072                                 reached = true;
2073                         }
2074
2075                         if (reached && (*x) < from) {
2076                                 return *x;
2077                         }
2078                 }
2079         }
2080
2081         return -1;
2082 }
2083
2084 boost::shared_ptr<Region>
2085 Playlist::find_next_region (samplepos_t sample, RegionPoint point, int dir)
2086 {
2087         RegionReadLock rlock (this);
2088         boost::shared_ptr<Region> ret;
2089         samplepos_t closest = max_samplepos;
2090
2091         bool end_iter = false;
2092
2093         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2094
2095                 if(end_iter) break;
2096
2097                 sampleoffset_t distance;
2098                 boost::shared_ptr<Region> r = (*i);
2099                 samplepos_t pos = 0;
2100
2101                 switch (point) {
2102                 case Start:
2103                         pos = r->first_sample ();
2104                         break;
2105                 case End:
2106                         pos = r->last_sample ();
2107                         break;
2108                 case SyncPoint:
2109                         pos = r->sync_position ();
2110                         break;
2111                 }
2112
2113                 switch (dir) {
2114                 case 1: /* forwards */
2115
2116                         if (pos > sample) {
2117                                 if ((distance = pos - sample) < closest) {
2118                                         closest = distance;
2119                                         ret = r;
2120                                         end_iter = true;
2121                                 }
2122                         }
2123
2124                         break;
2125
2126                 default: /* backwards */
2127
2128                         if (pos < sample) {
2129                                 if ((distance = sample - pos) < closest) {
2130                                         closest = distance;
2131                                         ret = r;
2132                                 }
2133                         } else {
2134                                 end_iter = true;
2135                         }
2136
2137                         break;
2138                 }
2139         }
2140
2141         return ret;
2142 }
2143
2144 samplepos_t
2145 Playlist::find_next_region_boundary (samplepos_t sample, int dir)
2146 {
2147         RegionReadLock rlock (this);
2148
2149         samplepos_t closest = max_samplepos;
2150         samplepos_t ret = -1;
2151
2152         if (dir > 0) {
2153
2154                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2155
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();
2160
2161                         if (first_sample > sample) {
2162
2163                                 distance = first_sample - sample;
2164
2165                                 if (distance < closest) {
2166                                         ret = first_sample;
2167                                         closest = distance;
2168                                 }
2169                         }
2170
2171                         if (last_sample > sample) {
2172
2173                                 distance = last_sample - sample;
2174
2175                                 if (distance < closest) {
2176                                         ret = last_sample;
2177                                         closest = distance;
2178                                 }
2179                         }
2180                 }
2181
2182         } else {
2183
2184                 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2185
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();
2190
2191                         if (last_sample < sample) {
2192
2193                                 distance = sample - last_sample;
2194
2195                                 if (distance < closest) {
2196                                         ret = last_sample;
2197                                         closest = distance;
2198                                 }
2199                         }
2200
2201                         if (first_sample < sample) {
2202
2203                                 distance = sample - first_sample;
2204
2205                                 if (distance < closest) {
2206                                         ret = first_sample;
2207                                         closest = distance;
2208                                 }
2209                         }
2210                 }
2211         }
2212
2213         return ret;
2214 }
2215
2216 /***********************************************************************/
2217
2218 void
2219 Playlist::mark_session_dirty ()
2220 {
2221         if (!in_set_state && !holding_state ()) {
2222                 _session.set_dirty();
2223         }
2224 }
2225
2226 void
2227 Playlist::rdiff (vector<Command*>& cmds) const
2228 {
2229         RegionReadLock rlock (const_cast<Playlist *> (this));
2230         Stateful::rdiff (cmds);
2231 }
2232
2233 void
2234 Playlist::clear_owned_changes ()
2235 {
2236         RegionReadLock rlock (this);
2237         Stateful::clear_owned_changes ();
2238 }
2239
2240 void
2241 Playlist::update (const RegionListProperty::ChangeRecord& change)
2242 {
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()));
2245
2246         freeze ();
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());
2250         }
2251         /* remove the removed regions */
2252         for (RegionListProperty::ChangeContainer::const_iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2253                 remove_region (*i);
2254         }
2255
2256         thaw ();
2257 }
2258
2259 int
2260 Playlist::set_state (const XMLNode& node, int version)
2261 {
2262         XMLNode *child;
2263         XMLNodeList nlist;
2264         XMLNodeConstIterator niter;
2265         XMLPropertyConstIterator piter;
2266         boost::shared_ptr<Region> region;
2267         string region_name;
2268         bool seen_region_nodes = false;
2269         int ret = 0;
2270
2271         in_set_state++;
2272
2273         if (node.name() != "Playlist") {
2274                 in_set_state--;
2275                 return -1;
2276         }
2277
2278         freeze ();
2279
2280         set_id (node);
2281
2282         std::string name;
2283         if (node.get_property (X_("name"), name)) {
2284                 _name = name;
2285                 _set_sort_id ();
2286         }
2287
2288         /* XXX legacy session: fix up later */
2289         node.get_property (X_("orig-diskstream-id"), _orig_track_id);
2290
2291         node.get_property (X_("orig-track-id"), _orig_track_id);
2292         node.get_property (X_("frozen"), _frozen);
2293
2294         node.get_property (X_("combine-ops"), _combine_ops);
2295
2296         string shared_ids;
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));
2304                         }
2305                 }
2306         }
2307
2308         clear (true);
2309
2310         nlist = node.children();
2311
2312         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2313
2314                 child = *niter;
2315
2316                 if (child->name() == "Region") {
2317
2318                         seen_region_nodes = true;
2319
2320                         ID id;
2321                         if (!child->get_property ("id", id)) {
2322                                 error << _("region state node has no ID, ignored") << endmsg;
2323                                 continue;
2324                         }
2325
2326                         if ((region = region_by_id (id))) {
2327
2328                                 region->suspend_property_changes ();
2329
2330                                 if (region->set_state (*child, version)) {
2331                                         region->resume_property_changes ();
2332                                         continue;
2333                                 }
2334
2335                         } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2336                                 region->suspend_property_changes ();
2337                         } else {
2338                                 error << _("Playlist: cannot create region from XML") << endmsg;
2339                                 return -1;
2340                         }
2341
2342                         {
2343                                 RegionWriteLock rlock (this);
2344                                 add_region_internal (region, region->position());
2345                         }
2346
2347                         region->resume_property_changes ();
2348
2349                 }
2350         }
2351
2352         if (seen_region_nodes && regions.empty()) {
2353                 ret = -1;
2354         }
2355
2356         thaw ();
2357         notify_contents_changed ();
2358
2359         in_set_state--;
2360         first_set_state = false;
2361
2362         return ret;
2363 }
2364
2365 XMLNode&
2366 Playlist::get_state()
2367 {
2368         return state (true);
2369 }
2370
2371 XMLNode&
2372 Playlist::get_template()
2373 {
2374         return state (false);
2375 }
2376
2377 /** @param full_state true to include regions in the returned state, otherwise false.
2378  */
2379 XMLNode&
2380 Playlist::state (bool full_state)
2381 {
2382         XMLNode *node = new XMLNode (X_("Playlist"));
2383
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);
2388
2389         string shared_ids;
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();
2393         }
2394         if (!shared_ids.empty()) {
2395                 shared_ids.erase(0,1);
2396         }
2397
2398         node->set_property (X_("shared-with-ids"), shared_ids);
2399         node->set_property (X_("frozen"), _frozen);
2400
2401         if (full_state) {
2402                 RegionReadLock rlock (this);
2403
2404                 node->set_property ("combine-ops", _combine_ops);
2405
2406                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2407                         node->add_child_nocopy ((*i)->get_state());
2408                 }
2409         }
2410
2411         if (_extra_xml) {
2412                 node->add_child_copy (*_extra_xml);
2413         }
2414
2415         return *node;
2416 }
2417
2418 bool
2419 Playlist::empty() const
2420 {
2421         RegionReadLock rlock (const_cast<Playlist *>(this));
2422         return regions.empty();
2423 }
2424
2425 uint32_t
2426 Playlist::n_regions() const
2427 {
2428         RegionReadLock rlock (const_cast<Playlist *>(this));
2429         return regions.size();
2430 }
2431
2432 /** @return true if the all_regions list is empty, ie this playlist
2433  *  has never had a region added to it.
2434  */
2435 bool
2436 Playlist::all_regions_empty() const
2437 {
2438         RegionReadLock rl (const_cast<Playlist *> (this));
2439         return all_regions.empty();
2440 }
2441
2442 pair<samplepos_t, samplepos_t>
2443 Playlist::get_extent () const
2444 {
2445         RegionReadLock rlock (const_cast<Playlist *>(this));
2446         return _get_extent ();
2447 }
2448
2449 pair<samplepos_t, samplepos_t>
2450 Playlist::get_extent_with_endspace () const
2451 {
2452         pair<samplepos_t, samplepos_t> l = get_extent();
2453         l.second += _end_space;
2454         return l;
2455 }
2456
2457 pair<samplepos_t, samplepos_t>
2458 Playlist::_get_extent () const
2459 {
2460         pair<samplepos_t, samplepos_t> ext (max_samplepos, 0);
2461
2462         if (regions.empty()) {
2463                 ext.first = 0;
2464                 return ext;
2465         }
2466
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;
2471                 }
2472                 if (e.second > ext.second) {
2473                         ext.second = e.second;
2474                 }
2475         }
2476
2477         return ext;
2478 }
2479
2480 string
2481 Playlist::bump_name (string name, Session &session)
2482 {
2483         string newname = name;
2484
2485         do {
2486                 newname = bump_name_once (newname, '.');
2487         } while (session.playlists()->by_name (newname)!=NULL);
2488
2489         return newname;
2490 }
2491
2492
2493 layer_t
2494 Playlist::top_layer() const
2495 {
2496         RegionReadLock rlock (const_cast<Playlist *> (this));
2497         layer_t top = 0;
2498
2499         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2500                 top = max (top, (*i)->layer());
2501         }
2502         return top;
2503 }
2504
2505 void
2506 Playlist::set_edit_mode (EditMode mode)
2507 {
2508         _edit_mode = mode;
2509 }
2510
2511 struct RelayerSort {
2512         bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2513                 return a->layering_index() < b->layering_index();
2514         }
2515 };
2516
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.
2520  */
2521 void
2522 Playlist::set_layer (boost::shared_ptr<Region> region, double new_layer)
2523 {
2524         /* Remove the layer we are setting from our region list, and sort it
2525          *  using the layer indeces.
2526          */
2527
2528         RegionList copy = regions.rlist();
2529         copy.remove (region);
2530         copy.sort (RelayerSort ());
2531
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) {
2536                         break;
2537                 }
2538                 ++i;
2539         }
2540
2541         copy.insert (i, region);
2542
2543         setup_layering_indices (copy);
2544 }
2545
2546 void
2547 Playlist::setup_layering_indices (RegionList const & regions)
2548 {
2549         uint64_t j = 0;
2550
2551         for (RegionList::const_iterator k = regions.begin(); k != regions.end(); ++k) {
2552                 (*k)->set_layering_index (j++);
2553         }
2554 }
2555
2556 struct LaterHigherSort {
2557         bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2558                 return a->position() < b->position();
2559         }
2560 };
2561
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.
2564  */
2565 void
2566 Playlist::relayer ()
2567 {
2568         /* never compute layers when setting from XML */
2569
2570         if (in_set_state) {
2571                 return;
2572         }
2573
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 */
2578
2579         /* how many pieces to divide this playlist's time up into */
2580         int const divisions = 512;
2581
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());
2588         }
2589
2590         /* hence the size of each time division */
2591         double const division_size = (end - start) / double (divisions);
2592
2593         vector<vector<RegionList> > layers;
2594         layers.push_back (vector<RegionList> (divisions));
2595
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()) {
2599                 case LaterHigher:
2600                         copy.sort (LaterHigherSort ());
2601                         break;
2602                 case Manual:
2603                         copy.sort (RelayerSort ());
2604                         break;
2605         }
2606
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()));
2610         }
2611
2612         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2613
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.
2617                  */
2618                 int start_division = 0;
2619                 int end_division = 0;
2620
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) {
2625                                 end_division--;
2626                         }
2627                 }
2628
2629                 assert (divisions == 0 || end_division < divisions);
2630
2631                 /* find the lowest layer that this region can go on */
2632                 size_t j = layers.size();
2633                 while (j > 0) {
2634                         /* try layer j - 1; it can go on if it overlaps no other region
2635                          * that is already on that layer
2636                          */
2637
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)) {
2643                                                 overlap = true;
2644                                                 break;
2645                                         }
2646                                         l++;
2647                                 }
2648
2649                                 if (overlap) {
2650                                         break;
2651                                 }
2652                         }
2653
2654                         if (overlap) {
2655                                 /* overlap, so we must use layer j */
2656                                 break;
2657                         }
2658
2659                         --j;
2660                 }
2661
2662                 if (j == layers.size()) {
2663                         /* we need a new layer for this region */
2664                         layers.push_back (vector<RegionList> (divisions));
2665                 }
2666
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);
2670                 }
2671
2672                 (*i)->set_layer (j);
2673         }
2674
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...
2680          */
2681         notify_layering_changed ();
2682
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
2685          * gone away.
2686          */
2687         setup_layering_indices (copy);
2688 }
2689
2690 void
2691 Playlist::raise_region (boost::shared_ptr<Region> region)
2692 {
2693         set_layer (region, region->layer() + 1.5);
2694         relayer ();
2695 }
2696
2697 void
2698 Playlist::lower_region (boost::shared_ptr<Region> region)
2699 {
2700         set_layer (region, region->layer() - 1.5);
2701         relayer ();
2702 }
2703
2704 void
2705 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2706 {
2707         set_layer (region, DBL_MAX);
2708         relayer ();
2709 }
2710
2711 void
2712 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2713 {
2714         set_layer (region, -0.5);
2715         relayer ();
2716 }
2717
2718 void
2719 Playlist::nudge_after (samplepos_t start, samplecnt_t distance, bool forwards)
2720 {
2721         RegionList::iterator i;
2722         bool moved = false;
2723
2724         _nudging = true;
2725
2726         {
2727                 RegionWriteLock rlock (const_cast<Playlist *> (this));
2728
2729                 for (i = regions.begin(); i != regions.end(); ++i) {
2730
2731                         if ((*i)->position() >= start) {
2732
2733                                 samplepos_t new_pos;
2734
2735                                 if (forwards) {
2736
2737                                         if ((*i)->last_sample() > max_samplepos - distance) {
2738                                                 new_pos = max_samplepos - (*i)->length();
2739                                         } else {
2740                                                 new_pos = (*i)->position() + distance;
2741                                         }
2742
2743                                 } else {
2744
2745                                         if ((*i)->position() > distance) {
2746                                                 new_pos = (*i)->position() - distance;
2747                                         } else {
2748                                                 new_pos = 0;
2749                                         }
2750                                 }
2751
2752                                 (*i)->set_position (new_pos);
2753                                 moved = true;
2754                         }
2755                 }
2756         }
2757
2758         if (moved) {
2759                 _nudging = false;
2760                 notify_contents_changed ();
2761         }
2762
2763 }
2764
2765 bool
2766 Playlist::uses_source (boost::shared_ptr<const Source> src, bool shallow) const
2767 {
2768         RegionReadLock rlock (const_cast<Playlist*> (this));
2769
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.
2776                  */
2777                 if ((*r)->uses_source (src, shallow)) {
2778                         return true;
2779                 }
2780         }
2781
2782         return false;
2783 }
2784
2785
2786 boost::shared_ptr<Region>
2787 Playlist::find_region (const ID& id) const
2788 {
2789         RegionReadLock rlock (const_cast<Playlist*> (this));
2790
2791         /* searches all regions currently in use by the playlist */
2792
2793         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2794                 if ((*i)->id() == id) {
2795                         return *i;
2796                 }
2797         }
2798
2799         return boost::shared_ptr<Region> ();
2800 }
2801
2802 uint32_t
2803 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2804 {
2805         RegionReadLock rlock (const_cast<Playlist*> (this));
2806         uint32_t cnt = 0;
2807
2808         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2809                 if ((*i) == r) {
2810                         cnt++;
2811                 }
2812         }
2813
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 */
2819                         ++cnt;
2820                         break;
2821                 }
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
2825                          */
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);
2829                                 if (!ps) continue;
2830                                 if (ps->playlist()->region_use_count(it->first)) {
2831                                         // break out of both loops
2832                                         return ++cnt;
2833                                 }
2834                         }
2835                 }
2836         }
2837         return cnt;
2838 }
2839
2840 boost::shared_ptr<Region>
2841 Playlist::region_by_id (const ID& id) const
2842 {
2843         /* searches all regions ever added to this playlist */
2844
2845         for (set<boost::shared_ptr<Region> >::const_iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2846                 if ((*i)->id() == id) {
2847                         return *i;
2848                 }
2849         }
2850         return boost::shared_ptr<Region> ();
2851 }
2852
2853 void
2854 Playlist::dump () const
2855 {
2856         boost::shared_ptr<Region> r;
2857
2858         cerr << "Playlist \"" << _name << "\" " << endl
2859              << regions.size() << " regions "
2860              << endl;
2861
2862         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2863                 r = *i;
2864                 cerr << "  " << r->name() << " ["
2865                      << r->start() << "+" << r->length()
2866                      << "] at "
2867                      << r->position()
2868                      << " on layer "
2869                      << r->layer ()
2870                      << endl;
2871         }
2872 }
2873
2874 void
2875 Playlist::set_frozen (bool yn)
2876 {
2877         _frozen = yn;
2878 }
2879
2880 void
2881 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2882 {
2883         bool moved = false;
2884
2885         if (region->locked()) {
2886                 return;
2887         }
2888
2889         _shuffling = true;
2890
2891         {
2892                 RegionWriteLock rlock (const_cast<Playlist*> (this));
2893
2894
2895                 if (dir > 0) {
2896
2897                         RegionList::iterator next;
2898
2899                         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2900                                 if ((*i) == region) {
2901                                         next = i;
2902                                         ++next;
2903
2904                                         if (next != regions.end()) {
2905
2906                                                 if ((*next)->locked()) {
2907                                                         break;
2908                                                 }
2909
2910                                                 samplepos_t new_pos;
2911
2912                                                 if ((*next)->position() != region->last_sample() + 1) {
2913                                                         /* they didn't used to touch, so after shuffle,
2914                                                          * just have them swap positions.
2915                                                          */
2916                                                         new_pos = (*next)->position();
2917                                                 } else {
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
2921                                                          * it is moved.
2922                                                          */
2923                                                         new_pos = region->position() + (*next)->length();
2924                                                 }
2925
2926                                                 (*next)->set_position (region->position());
2927                                                 region->set_position (new_pos);
2928
2929                                                 /* avoid a full sort */
2930
2931                                                 regions.erase (i); // removes the region from the list */
2932                                                 next++;
2933                                                 regions.insert (next, region); // adds it back after next
2934
2935                                                 moved = true;
2936                                         }
2937                                         break;
2938                                 }
2939                         }
2940                 } else {
2941
2942                         RegionList::iterator prev = regions.end();
2943
2944                         for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2945                                 if ((*i) == region) {
2946
2947                                         if (prev != regions.end()) {
2948
2949                                                 if ((*prev)->locked()) {
2950                                                         break;
2951                                                 }
2952
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.
2957                                                          */
2958                                                         new_pos = region->position();
2959                                                 } else {
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
2963                                                          */
2964                                                         new_pos = (*prev)->position() + region->length();
2965                                                 }
2966
2967                                                 region->set_position ((*prev)->position());
2968                                                 (*prev)->set_position (new_pos);
2969
2970                                                 /* avoid a full sort */
2971
2972                                                 regions.erase (i); // remove region
2973                                                 regions.insert (prev, region); // insert region before prev
2974
2975                                                 moved = true;
2976                                         }
2977
2978                                         break;
2979                                 }
2980                         }
2981                 }
2982         }
2983
2984         _shuffling = false;
2985
2986         if (moved) {
2987
2988                 relayer ();
2989                 notify_contents_changed();
2990         }
2991
2992 }
2993
2994 bool
2995 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2996 {
2997         RegionReadLock rlock (const_cast<Playlist*> (this));
2998
2999         if (regions.size() > 1) {
3000                 return true;
3001         }
3002
3003         return false;
3004 }
3005
3006 void
3007 Playlist::ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
3008 {
3009         ripple_locked (at, distance, exclude);
3010 }
3011
3012 void
3013 Playlist::update_after_tempo_map_change ()
3014 {
3015         RegionWriteLock rlock (const_cast<Playlist*> (this));
3016         RegionList copy (regions.rlist());
3017
3018         freeze ();
3019
3020         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
3021                 (*i)->update_after_tempo_map_change ();
3022         }
3023         /* possibly causes a contents changed notification (flush_notifications()) */
3024         thaw ();
3025 }
3026
3027 void
3028 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
3029 {
3030         RegionReadLock rl (this);
3031         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3032                 s (*i);
3033         }
3034 }
3035
3036 bool
3037 Playlist::has_region_at (samplepos_t const p) const
3038 {
3039         RegionReadLock (const_cast<Playlist *> (this));
3040
3041         RegionList::const_iterator i = regions.begin ();
3042         while (i != regions.end() && !(*i)->covers (p)) {
3043                 ++i;
3044         }
3045
3046         return (i != regions.end());
3047 }
3048
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.
3053  */
3054 samplepos_t
3055 Playlist::find_next_top_layer_position (samplepos_t t) const
3056 {
3057         RegionReadLock rlock (const_cast<Playlist *> (this));
3058
3059         layer_t const top = top_layer ();
3060
3061         RegionList copy = regions.rlist ();
3062         copy.sort (RegionSortByPosition ());
3063
3064         for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3065                 if ((*i)->position() >= t && (*i)->layer() == top) {
3066                         return (*i)->position();
3067                 }
3068         }
3069
3070         return max_samplepos;
3071 }
3072
3073 boost::shared_ptr<Region>
3074 Playlist::combine (const RegionList& r)
3075 {
3076         PropertyList plist;
3077         uint32_t channels = 0;
3078         uint32_t layer = 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;
3083         string parent_name;
3084         string child_name;
3085         uint32_t max_level = 0;
3086
3087         /* find the maximum depth of all the regions we're combining */
3088
3089         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3090                 max_level = max (max_level, (*i)->max_source_level());
3091         }
3092
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);
3095
3096         boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, parent_name, true);
3097
3098         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3099                 earliest_position = min (earliest_position, (*i)->position());
3100         }
3101
3102         /* enable this so that we do not try to create xfades etc. as we add
3103          * regions
3104          */
3105
3106         pl->in_partition = true;
3107
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.
3111          */
3112         RegionList sorted(r);
3113         sorted.sort(RegionSortByLayerAndPosition());
3114
3115         for (RegionList::const_iterator i = sorted.begin(); i != sorted.end(); ++i) {
3116
3117                 /* copy the region */
3118
3119                 boost::shared_ptr<Region> original_region = (*i);
3120                 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
3121
3122                 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
3123                 originals.push_back (original_region);
3124                 copies.push_back (copied_region);
3125
3126                 RegionFactory::add_compound_association (original_region, copied_region);
3127
3128                 /* make position relative to zero */
3129
3130                 pl->add_region (copied_region, original_region->position() - earliest_position);
3131                 copied_region->set_layer (original_region->layer ());
3132
3133                 /* use the maximum number of channels for any region */
3134
3135                 channels = max (channels, original_region->n_channels());
3136
3137                 /* it will go above the layer of the highest existing region */
3138
3139                 layer = max (layer, original_region->layer());
3140         }
3141
3142         pl->in_partition = false;
3143
3144         pre_combine (copies);
3145
3146         /* now create a new PlaylistSource for each channel in the new playlist */
3147
3148         SourceList sources;
3149         pair<samplepos_t,samplepos_t> extent = pl->get_extent();
3150
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));
3153
3154         }
3155
3156         /* now a new whole-file region using the list of sources */
3157
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);
3162
3163         boost::shared_ptr<Region> parent_region = RegionFactory::create (sources, plist, true);
3164
3165         /* now the non-whole-file region that we will actually use in the playlist */
3166
3167         plist.clear ();
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);
3172
3173         boost::shared_ptr<Region> compound_region = RegionFactory::create (parent_region, plist, true);
3174
3175         /* remove all the selected regions from the current playlist */
3176
3177         freeze ();
3178
3179         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3180                 remove_region (*i);
3181         }
3182
3183         /* do type-specific stuff with the originals and the new compound region */
3184
3185         post_combine (originals, compound_region);
3186
3187         /* add the new region at the right location */
3188
3189         add_region (compound_region, earliest_position);
3190
3191         _combine_ops++;
3192
3193         thaw ();
3194
3195         return compound_region;
3196 }
3197
3198 void
3199 Playlist::uncombine (boost::shared_ptr<Region> target)
3200 {
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;
3205
3206         // (1) check that its really a compound region
3207
3208         if ((pls = boost::dynamic_pointer_cast<PlaylistSource>(target->source (0))) == 0) {
3209                 return;
3210         }
3211
3212         pl = pls->playlist();
3213
3214         samplepos_t adjusted_start = 0; // gcc isn't smart enough
3215         samplepos_t adjusted_end = 0;   // gcc isn't smart enough
3216
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.
3220          *
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.
3224          */
3225
3226         // (2) get all the original regions
3227
3228         const RegionList& rl (pl->region_list_property().rlist());
3229         RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
3230         sampleoffset_t move_offset = 0;
3231
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.
3236
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
3240            instead.
3241         */
3242         bool same_playlist = (pls->original() == id());
3243
3244         for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
3245
3246                 boost::shared_ptr<Region> current (*i);
3247
3248                 RegionFactory::CompoundAssociations::iterator ca = cassocs.find (*i);
3249
3250                 if (ca == cassocs.end()) {
3251                         continue;
3252                 }
3253
3254                 boost::shared_ptr<Region> original (ca->second);
3255                 cassocs.erase(ca);
3256                 bool modified_region;
3257
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();
3262                 }
3263
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);
3270                 }
3271
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.
3275                  */
3276
3277                 original->clear_changes ();
3278                 modified_region = false;
3279
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
3284                          */
3285                         continue;
3286
3287                 case Evoral::OverlapInternal:
3288                         /* overlap is just a small piece inside the
3289                          * original so trim both ends
3290                          */
3291                         original->trim_to (adjusted_start, adjusted_end - adjusted_start);
3292                         modified_region = true;
3293                         break;
3294
3295                 case Evoral::OverlapExternal:
3296                         /* overlap fully covers original, so leave it as is */
3297                         break;
3298
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;
3303                         break;
3304
3305                 case Evoral::OverlapStart:
3306                         /* overlap covers start but ends within, so
3307                          * trim the end of the region.
3308                          */
3309                         original->trim_end (adjusted_end);
3310                         modified_region = true;
3311                         break;
3312                 }
3313
3314                 if (move_offset) {
3315                         /* fix the position to match any movement of the compound region. */
3316                         original->set_position (original->position() + move_offset);
3317                         modified_region = true;
3318                 }
3319
3320                 if (modified_region) {
3321                         _session.add_command (new StatefulDiffCommand (original));
3322                 }
3323
3324                 /* and add to the list of regions waiting to be
3325                  * re-inserted
3326                  */
3327
3328                 originals.push_back (original);
3329                 old_and_new_regions.push_back (TwoRegions (*i, original));
3330         }
3331
3332         pre_uncombine (originals, target);
3333
3334         in_partition = true;
3335         freeze ();
3336
3337         // (3) remove the compound region
3338
3339         remove_region (target);
3340
3341         // (4) add the constituent regions
3342
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);
3348                 }
3349         }
3350
3351         in_partition = false;
3352         thaw ();
3353 }
3354
3355 void
3356 Playlist::fade_range (list<AudioRange>& ranges)
3357 {
3358         RegionReadLock rlock (this);
3359         for (list<AudioRange>::iterator r = ranges.begin(); r != ranges.end(); ) {
3360                 list<AudioRange>::iterator tmpr = r;
3361                 ++tmpr;
3362                 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ) {
3363                         RegionList::const_iterator tmpi = i;
3364                         ++tmpi;
3365                         (*i)->fade_range ((*r).start, (*r).end);
3366                         i = tmpi;
3367                 }
3368                 r = tmpr;
3369         }
3370 }
3371
3372 uint32_t
3373 Playlist::max_source_level () const
3374 {
3375         RegionReadLock rlock (const_cast<Playlist *> (this));
3376         uint32_t lvl = 0;
3377
3378         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3379                 lvl = max (lvl, (*i)->max_source_level());
3380         }
3381
3382         return lvl;
3383 }
3384
3385 void
3386 Playlist::set_orig_track_id (const PBD::ID& id)
3387 {
3388         if (shared_with(id)) {
3389                 // Swap 'shared_id' / origin_track_id
3390                 unshare_with (id);
3391                 share_with (_orig_track_id);
3392         }
3393         _orig_track_id = id;
3394 }
3395
3396 void
3397 Playlist::share_with (const PBD::ID& id)
3398 {
3399         if (!shared_with(id)) {
3400                 _shared_with_ids.push_back (id);
3401         }
3402 }
3403
3404 void
3405 Playlist::unshare_with (const PBD::ID& id)
3406 {
3407         list<PBD::ID>::iterator it = _shared_with_ids.begin ();
3408         while (it != _shared_with_ids.end()) {
3409                 if (*it == id) {
3410                         _shared_with_ids.erase (it);
3411                         break;
3412                 }
3413                 ++it;
3414         }
3415 }
3416
3417 bool
3418 Playlist::shared_with (const PBD::ID& id) const
3419 {
3420         bool shared = false;
3421         list<PBD::ID>::const_iterator it = _shared_with_ids.begin ();
3422         while (it != _shared_with_ids.end() && !shared) {
3423                 if (*it == id) {
3424                         shared = true;
3425                 }
3426                 ++it;
3427         }
3428
3429         return shared;
3430 }
3431
3432 void
3433 Playlist::reset_shares ()
3434 {
3435         _shared_with_ids.clear();
3436 }
3437
3438 /** Take a list of ranges, coalesce any that can be coalesced, then call
3439  *  check_crossfades for each one.
3440  */
3441 void
3442 Playlist::coalesce_and_check_crossfades (list<Evoral::Range<samplepos_t> > ranges)
3443 {
3444         /* XXX: it's a shame that this coalesce algorithm also exists in
3445          * TimeSelection::consolidate().
3446          */
3447
3448         /* XXX: xfade: this is implemented in Evoral::RangeList */
3449
3450 restart:
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) {
3453
3454                         if (i == j) {
3455                                 continue;
3456                         }
3457
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);
3462                                 ranges.erase (j);
3463                                 goto restart;
3464                         }
3465                 }
3466         }
3467 }
3468
3469 void
3470 Playlist::set_capture_insertion_in_progress (bool yn)
3471 {
3472         _capture_insertion_underway = yn;
3473 }