fix playback of newly added/modified MIDI data
[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::contents)) {
1790                 send_contents = true;
1791         }
1792
1793         if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1794                 notify_region_moved (region);
1795         } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1796                 notify_region_end_trimmed (region);
1797         } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1798                 notify_region_start_trimmed (region);
1799         }
1800
1801         /* don't notify about layer changes, since we are the only object that can initiate
1802          * them, and we notify in ::relayer()
1803          */
1804
1805         if (what_changed.contains (our_interests)) {
1806                 save = true;
1807         }
1808
1809         if (send_contents || save) {
1810                 notify_contents_changed ();
1811         }
1812
1813         mark_session_dirty ();
1814
1815         return save;
1816 }
1817
1818 void
1819 Playlist::drop_regions ()
1820 {
1821         RegionWriteLock rl (this);
1822         regions.clear ();
1823         all_regions.clear ();
1824 }
1825
1826 void
1827 Playlist::sync_all_regions_with_regions ()
1828 {
1829         RegionWriteLock rl (this);
1830
1831         all_regions.clear ();
1832
1833         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1834                 all_regions.insert (*i);
1835         }
1836 }
1837
1838 void
1839 Playlist::clear (bool with_signals)
1840 {
1841         {
1842                 RegionWriteLock rl (this);
1843
1844                 region_state_changed_connections.drop_connections ();
1845                 region_drop_references_connections.drop_connections ();
1846
1847                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1848                         pending_removes.insert (*i);
1849                 }
1850
1851                 regions.clear ();
1852
1853                 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1854                         remove_dependents (*s);
1855                 }
1856         }
1857
1858         if (with_signals) {
1859
1860                 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1861                         RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1862                 }
1863
1864                 pending_removes.clear ();
1865                 pending_contents_change = false;
1866                 ContentsChanged ();
1867         }
1868
1869 }
1870
1871 /* *********************************************************************
1872 FINDING THINGS
1873 **********************************************************************/
1874
1875 boost::shared_ptr<RegionList>
1876 Playlist::region_list()
1877 {
1878         RegionReadLock rlock (this);
1879         boost::shared_ptr<RegionList> rlist (new RegionList (regions.rlist ()));
1880         return rlist;
1881 }
1882
1883 void
1884 Playlist::deep_sources (std::set<boost::shared_ptr<Source> >& sources) const
1885 {
1886         RegionReadLock rlock (const_cast<Playlist*>(this));
1887
1888         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1889                 (*i)->deep_sources (sources);
1890         }
1891 }
1892
1893 boost::shared_ptr<RegionList>
1894 Playlist::regions_at (samplepos_t sample)
1895 {
1896         RegionReadLock rlock (this);
1897         return find_regions_at (sample);
1898 }
1899
1900 uint32_t
1901 Playlist::count_regions_at (samplepos_t sample) const
1902 {
1903         RegionReadLock rlock (const_cast<Playlist*>(this));
1904         uint32_t cnt = 0;
1905
1906         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1907                 if ((*i)->covers (sample)) {
1908                         cnt++;
1909                 }
1910         }
1911
1912         return cnt;
1913 }
1914
1915 boost::shared_ptr<Region>
1916 Playlist::top_region_at (samplepos_t sample)
1917 {
1918         RegionReadLock rlock (this);
1919         boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1920         boost::shared_ptr<Region> region;
1921
1922         if (rlist->size()) {
1923                 RegionSortByLayer cmp;
1924                 rlist->sort (cmp);
1925                 region = rlist->back();
1926         }
1927
1928         return region;
1929 }
1930
1931 boost::shared_ptr<Region>
1932 Playlist::top_unmuted_region_at (samplepos_t sample)
1933 {
1934         RegionReadLock rlock (this);
1935         boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1936
1937         for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1938
1939                 RegionList::iterator tmp = i;
1940
1941                 ++tmp;
1942
1943                 if ((*i)->muted()) {
1944                         rlist->erase (i);
1945                 }
1946
1947                 i = tmp;
1948         }
1949
1950         boost::shared_ptr<Region> region;
1951
1952         if (rlist->size()) {
1953                 RegionSortByLayer cmp;
1954                 rlist->sort (cmp);
1955                 region = rlist->back();
1956         }
1957
1958         return region;
1959 }
1960
1961 boost::shared_ptr<RegionList>
1962 Playlist::find_regions_at (samplepos_t sample)
1963 {
1964         /* Caller must hold lock */
1965
1966         boost::shared_ptr<RegionList> rlist (new RegionList);
1967
1968         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1969                 if ((*i)->covers (sample)) {
1970                         rlist->push_back (*i);
1971                 }
1972         }
1973
1974         return rlist;
1975 }
1976
1977 boost::shared_ptr<RegionList>
1978 Playlist::regions_with_start_within (Evoral::Range<samplepos_t> range)
1979 {
1980         RegionReadLock rlock (this);
1981         boost::shared_ptr<RegionList> rlist (new RegionList);
1982
1983         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1984                 if ((*i)->first_sample() >= range.from && (*i)->first_sample() <= range.to) {
1985                         rlist->push_back (*i);
1986                 }
1987         }
1988
1989         return rlist;
1990 }
1991
1992 boost::shared_ptr<RegionList>
1993 Playlist::regions_with_end_within (Evoral::Range<samplepos_t> range)
1994 {
1995         RegionReadLock rlock (this);
1996         boost::shared_ptr<RegionList> rlist (new RegionList);
1997
1998         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1999                 if ((*i)->last_sample() >= range.from && (*i)->last_sample() <= range.to) {
2000                         rlist->push_back (*i);
2001                 }
2002         }
2003
2004         return rlist;
2005 }
2006
2007 boost::shared_ptr<RegionList>
2008 Playlist::regions_touched (samplepos_t start, samplepos_t end)
2009 {
2010         RegionReadLock rlock (this);
2011         return regions_touched_locked (start, end);
2012 }
2013
2014 boost::shared_ptr<RegionList>
2015 Playlist::regions_touched_locked (samplepos_t start, samplepos_t end)
2016 {
2017         boost::shared_ptr<RegionList> rlist (new RegionList);
2018
2019         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2020                 if ((*i)->coverage (start, end) != Evoral::OverlapNone) {
2021                         rlist->push_back (*i);
2022                 }
2023         }
2024
2025         return rlist;
2026 }
2027
2028 samplepos_t
2029 Playlist::find_next_transient (samplepos_t from, int dir)
2030 {
2031         RegionReadLock rlock (this);
2032         AnalysisFeatureList points;
2033         AnalysisFeatureList these_points;
2034
2035         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2036                 if (dir > 0) {
2037                         if ((*i)->last_sample() < from) {
2038                                 continue;
2039                         }
2040                 } else {
2041                         if ((*i)->first_sample() > from) {
2042                                 continue;
2043                         }
2044                 }
2045
2046                 (*i)->get_transients (these_points);
2047
2048                 /* add first sample, just, err, because */
2049
2050                 these_points.push_back ((*i)->first_sample());
2051
2052                 points.insert (points.end(), these_points.begin(), these_points.end());
2053                 these_points.clear ();
2054         }
2055
2056         if (points.empty()) {
2057                 return -1;
2058         }
2059
2060         TransientDetector::cleanup_transients (points, _session.sample_rate(), 3.0);
2061         bool reached = false;
2062
2063         if (dir > 0) {
2064                 for (AnalysisFeatureList::const_iterator x = points.begin(); x != points.end(); ++x) {
2065                         if ((*x) >= from) {
2066                                 reached = true;
2067                         }
2068
2069                         if (reached && (*x) > from) {
2070                                 return *x;
2071                         }
2072                 }
2073         } else {
2074                 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2075                         if ((*x) <= from) {
2076                                 reached = true;
2077                         }
2078
2079                         if (reached && (*x) < from) {
2080                                 return *x;
2081                         }
2082                 }
2083         }
2084
2085         return -1;
2086 }
2087
2088 boost::shared_ptr<Region>
2089 Playlist::find_next_region (samplepos_t sample, RegionPoint point, int dir)
2090 {
2091         RegionReadLock rlock (this);
2092         boost::shared_ptr<Region> ret;
2093         samplepos_t closest = max_samplepos;
2094
2095         bool end_iter = false;
2096
2097         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2098
2099                 if(end_iter) break;
2100
2101                 sampleoffset_t distance;
2102                 boost::shared_ptr<Region> r = (*i);
2103                 samplepos_t pos = 0;
2104
2105                 switch (point) {
2106                 case Start:
2107                         pos = r->first_sample ();
2108                         break;
2109                 case End:
2110                         pos = r->last_sample ();
2111                         break;
2112                 case SyncPoint:
2113                         pos = r->sync_position ();
2114                         break;
2115                 }
2116
2117                 switch (dir) {
2118                 case 1: /* forwards */
2119
2120                         if (pos > sample) {
2121                                 if ((distance = pos - sample) < closest) {
2122                                         closest = distance;
2123                                         ret = r;
2124                                         end_iter = true;
2125                                 }
2126                         }
2127
2128                         break;
2129
2130                 default: /* backwards */
2131
2132                         if (pos < sample) {
2133                                 if ((distance = sample - pos) < closest) {
2134                                         closest = distance;
2135                                         ret = r;
2136                                 }
2137                         } else {
2138                                 end_iter = true;
2139                         }
2140
2141                         break;
2142                 }
2143         }
2144
2145         return ret;
2146 }
2147
2148 samplepos_t
2149 Playlist::find_next_region_boundary (samplepos_t sample, int dir)
2150 {
2151         RegionReadLock rlock (this);
2152
2153         samplepos_t closest = max_samplepos;
2154         samplepos_t ret = -1;
2155
2156         if (dir > 0) {
2157
2158                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2159
2160                         boost::shared_ptr<Region> r = (*i);
2161                         sampleoffset_t distance;
2162                         const samplepos_t first_sample = r->first_sample();
2163                         const samplepos_t last_sample = r->last_sample();
2164
2165                         if (first_sample > sample) {
2166
2167                                 distance = first_sample - sample;
2168
2169                                 if (distance < closest) {
2170                                         ret = first_sample;
2171                                         closest = distance;
2172                                 }
2173                         }
2174
2175                         if (last_sample > sample) {
2176
2177                                 distance = last_sample - sample;
2178
2179                                 if (distance < closest) {
2180                                         ret = last_sample;
2181                                         closest = distance;
2182                                 }
2183                         }
2184                 }
2185
2186         } else {
2187
2188                 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2189
2190                         boost::shared_ptr<Region> r = (*i);
2191                         sampleoffset_t distance;
2192                         const samplepos_t first_sample = r->first_sample();
2193                         const samplepos_t last_sample = r->last_sample();
2194
2195                         if (last_sample < sample) {
2196
2197                                 distance = sample - last_sample;
2198
2199                                 if (distance < closest) {
2200                                         ret = last_sample;
2201                                         closest = distance;
2202                                 }
2203                         }
2204
2205                         if (first_sample < sample) {
2206
2207                                 distance = sample - first_sample;
2208
2209                                 if (distance < closest) {
2210                                         ret = first_sample;
2211                                         closest = distance;
2212                                 }
2213                         }
2214                 }
2215         }
2216
2217         return ret;
2218 }
2219
2220 /***********************************************************************/
2221
2222 void
2223 Playlist::mark_session_dirty ()
2224 {
2225         if (!in_set_state && !holding_state ()) {
2226                 _session.set_dirty();
2227         }
2228 }
2229
2230 void
2231 Playlist::rdiff (vector<Command*>& cmds) const
2232 {
2233         RegionReadLock rlock (const_cast<Playlist *> (this));
2234         Stateful::rdiff (cmds);
2235 }
2236
2237 void
2238 Playlist::clear_owned_changes ()
2239 {
2240         RegionReadLock rlock (this);
2241         Stateful::clear_owned_changes ();
2242 }
2243
2244 void
2245 Playlist::update (const RegionListProperty::ChangeRecord& change)
2246 {
2247         DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2248                                 name(), change.added.size(), change.removed.size()));
2249
2250         freeze ();
2251         /* add the added regions */
2252         for (RegionListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
2253                 add_region_internal ((*i), (*i)->position());
2254         }
2255         /* remove the removed regions */
2256         for (RegionListProperty::ChangeContainer::const_iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2257                 remove_region (*i);
2258         }
2259
2260         thaw ();
2261 }
2262
2263 int
2264 Playlist::set_state (const XMLNode& node, int version)
2265 {
2266         XMLNode *child;
2267         XMLNodeList nlist;
2268         XMLNodeConstIterator niter;
2269         XMLPropertyConstIterator piter;
2270         boost::shared_ptr<Region> region;
2271         string region_name;
2272         bool seen_region_nodes = false;
2273         int ret = 0;
2274
2275         in_set_state++;
2276
2277         if (node.name() != "Playlist") {
2278                 in_set_state--;
2279                 return -1;
2280         }
2281
2282         freeze ();
2283
2284         set_id (node);
2285
2286         std::string name;
2287         if (node.get_property (X_("name"), name)) {
2288                 _name = name;
2289                 _set_sort_id ();
2290         }
2291
2292         /* XXX legacy session: fix up later */
2293         node.get_property (X_("orig-diskstream-id"), _orig_track_id);
2294
2295         node.get_property (X_("orig-track-id"), _orig_track_id);
2296         node.get_property (X_("frozen"), _frozen);
2297
2298         node.get_property (X_("combine-ops"), _combine_ops);
2299
2300         string shared_ids;
2301         if (node.get_property (X_("shared-with-ids"), shared_ids)) {
2302                 if (!shared_ids.empty()) {
2303                         vector<string> result;
2304                         ::split (shared_ids, result, ',');
2305                         vector<string>::iterator it = result.begin();
2306                         for (; it != result.end(); ++it) {
2307                                 _shared_with_ids.push_back (PBD::ID(*it));
2308                         }
2309                 }
2310         }
2311
2312         clear (true);
2313
2314         nlist = node.children();
2315
2316         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2317
2318                 child = *niter;
2319
2320                 if (child->name() == "Region") {
2321
2322                         seen_region_nodes = true;
2323
2324                         ID id;
2325                         if (!child->get_property ("id", id)) {
2326                                 error << _("region state node has no ID, ignored") << endmsg;
2327                                 continue;
2328                         }
2329
2330                         if ((region = region_by_id (id))) {
2331
2332                                 region->suspend_property_changes ();
2333
2334                                 if (region->set_state (*child, version)) {
2335                                         region->resume_property_changes ();
2336                                         continue;
2337                                 }
2338
2339                         } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2340                                 region->suspend_property_changes ();
2341                         } else {
2342                                 error << _("Playlist: cannot create region from XML") << endmsg;
2343                                 return -1;
2344                         }
2345
2346                         {
2347                                 RegionWriteLock rlock (this);
2348                                 add_region_internal (region, region->position());
2349                         }
2350
2351                         region->resume_property_changes ();
2352
2353                 }
2354         }
2355
2356         if (seen_region_nodes && regions.empty()) {
2357                 ret = -1;
2358         }
2359
2360         thaw ();
2361         notify_contents_changed ();
2362
2363         in_set_state--;
2364         first_set_state = false;
2365
2366         return ret;
2367 }
2368
2369 XMLNode&
2370 Playlist::get_state()
2371 {
2372         return state (true);
2373 }
2374
2375 XMLNode&
2376 Playlist::get_template()
2377 {
2378         return state (false);
2379 }
2380
2381 /** @param full_state true to include regions in the returned state, otherwise false.
2382  */
2383 XMLNode&
2384 Playlist::state (bool full_state)
2385 {
2386         XMLNode *node = new XMLNode (X_("Playlist"));
2387
2388         node->set_property (X_("id"), id());
2389         node->set_property (X_("name"), name());
2390         node->set_property (X_("type"), _type);
2391         node->set_property (X_("orig-track-id"), _orig_track_id);
2392
2393         string shared_ids;
2394         list<PBD::ID>::const_iterator it = _shared_with_ids.begin();
2395         for (; it != _shared_with_ids.end(); ++it) {
2396                 shared_ids += "," + (*it).to_s();
2397         }
2398         if (!shared_ids.empty()) {
2399                 shared_ids.erase(0,1);
2400         }
2401
2402         node->set_property (X_("shared-with-ids"), shared_ids);
2403         node->set_property (X_("frozen"), _frozen);
2404
2405         if (full_state) {
2406                 RegionReadLock rlock (this);
2407
2408                 node->set_property ("combine-ops", _combine_ops);
2409
2410                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2411                         node->add_child_nocopy ((*i)->get_state());
2412                 }
2413         }
2414
2415         if (_extra_xml) {
2416                 node->add_child_copy (*_extra_xml);
2417         }
2418
2419         return *node;
2420 }
2421
2422 bool
2423 Playlist::empty() const
2424 {
2425         RegionReadLock rlock (const_cast<Playlist *>(this));
2426         return regions.empty();
2427 }
2428
2429 uint32_t
2430 Playlist::n_regions() const
2431 {
2432         RegionReadLock rlock (const_cast<Playlist *>(this));
2433         return regions.size();
2434 }
2435
2436 /** @return true if the all_regions list is empty, ie this playlist
2437  *  has never had a region added to it.
2438  */
2439 bool
2440 Playlist::all_regions_empty() const
2441 {
2442         RegionReadLock rl (const_cast<Playlist *> (this));
2443         return all_regions.empty();
2444 }
2445
2446 pair<samplepos_t, samplepos_t>
2447 Playlist::get_extent () const
2448 {
2449         RegionReadLock rlock (const_cast<Playlist *>(this));
2450         return _get_extent ();
2451 }
2452
2453 pair<samplepos_t, samplepos_t>
2454 Playlist::get_extent_with_endspace () const
2455 {
2456         pair<samplepos_t, samplepos_t> l = get_extent();
2457         l.second += _end_space;
2458         return l;
2459 }
2460
2461 pair<samplepos_t, samplepos_t>
2462 Playlist::_get_extent () const
2463 {
2464         pair<samplepos_t, samplepos_t> ext (max_samplepos, 0);
2465
2466         if (regions.empty()) {
2467                 ext.first = 0;
2468                 return ext;
2469         }
2470
2471         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2472                 pair<samplepos_t, samplepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2473                 if (e.first < ext.first) {
2474                         ext.first = e.first;
2475                 }
2476                 if (e.second > ext.second) {
2477                         ext.second = e.second;
2478                 }
2479         }
2480
2481         return ext;
2482 }
2483
2484 string
2485 Playlist::bump_name (string name, Session &session)
2486 {
2487         string newname = name;
2488
2489         do {
2490                 newname = bump_name_once (newname, '.');
2491         } while (session.playlists()->by_name (newname)!=NULL);
2492
2493         return newname;
2494 }
2495
2496
2497 layer_t
2498 Playlist::top_layer() const
2499 {
2500         RegionReadLock rlock (const_cast<Playlist *> (this));
2501         layer_t top = 0;
2502
2503         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2504                 top = max (top, (*i)->layer());
2505         }
2506         return top;
2507 }
2508
2509 void
2510 Playlist::set_edit_mode (EditMode mode)
2511 {
2512         _edit_mode = mode;
2513 }
2514
2515 struct RelayerSort {
2516         bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2517                 return a->layering_index() < b->layering_index();
2518         }
2519 };
2520
2521 /** Set a new layer for a region.  This adjusts the layering indices of all
2522  *  regions in the playlist to put the specified region in the appropriate
2523  *  place.  The actual layering will be fixed up when relayer() happens.
2524  */
2525 void
2526 Playlist::set_layer (boost::shared_ptr<Region> region, double new_layer)
2527 {
2528         /* Remove the layer we are setting from our region list, and sort it
2529          *  using the layer indeces.
2530          */
2531
2532         RegionList copy = regions.rlist();
2533         copy.remove (region);
2534         copy.sort (RelayerSort ());
2535
2536         /* Put region back in the right place */
2537         RegionList::iterator i = copy.begin();
2538         while (i != copy.end ()) {
2539                 if ((*i)->layer() > new_layer) {
2540                         break;
2541                 }
2542                 ++i;
2543         }
2544
2545         copy.insert (i, region);
2546
2547         setup_layering_indices (copy);
2548 }
2549
2550 void
2551 Playlist::setup_layering_indices (RegionList const & regions)
2552 {
2553         uint64_t j = 0;
2554
2555         for (RegionList::const_iterator k = regions.begin(); k != regions.end(); ++k) {
2556                 (*k)->set_layering_index (j++);
2557         }
2558 }
2559
2560 struct LaterHigherSort {
2561         bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2562                 return a->position() < b->position();
2563         }
2564 };
2565
2566 /** Take the layering indices of each of our regions, compute the layers
2567  *  that they should be on, and write the layers back to the regions.
2568  */
2569 void
2570 Playlist::relayer ()
2571 {
2572         /* never compute layers when setting from XML */
2573
2574         if (in_set_state) {
2575                 return;
2576         }
2577
2578         /* Build up a new list of regions on each layer, stored in a set of lists
2579          * each of which represent some period of time on some layer.  The idea
2580          * is to avoid having to search the entire region list to establish whether
2581          * each region overlaps another */
2582
2583         /* how many pieces to divide this playlist's time up into */
2584         int const divisions = 512;
2585
2586         /* find the start and end positions of the regions on this playlist */
2587         samplepos_t start = INT64_MAX;
2588         samplepos_t end = 0;
2589         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2590                 start = min (start, (*i)->position());
2591                 end = max (end, (*i)->position() + (*i)->length());
2592         }
2593
2594         /* hence the size of each time division */
2595         double const division_size = (end - start) / double (divisions);
2596
2597         vector<vector<RegionList> > layers;
2598         layers.push_back (vector<RegionList> (divisions));
2599
2600         /* Sort our regions into layering index order (for manual layering) or position order (for later is higher)*/
2601         RegionList copy = regions.rlist();
2602         switch (Config->get_layer_model()) {
2603                 case LaterHigher:
2604                         copy.sort (LaterHigherSort ());
2605                         break;
2606                 case Manual:
2607                         copy.sort (RelayerSort ());
2608                         break;
2609         }
2610
2611         DEBUG_TRACE (DEBUG::Layering, "relayer() using:\n");
2612         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2613                 DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1 %2\n", (*i)->name(), (*i)->layering_index()));
2614         }
2615
2616         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2617
2618                 /* find the time divisions that this region covers; if there are no regions on the list,
2619                  * division_size will equal 0 and in this case we'll just say that
2620                  * start_division = end_division = 0.
2621                  */
2622                 int start_division = 0;
2623                 int end_division = 0;
2624
2625                 if (division_size > 0) {
2626                         start_division = floor ( ((*i)->position() - start) / division_size);
2627                         end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2628                         if (end_division == divisions) {
2629                                 end_division--;
2630                         }
2631                 }
2632
2633                 assert (divisions == 0 || end_division < divisions);
2634
2635                 /* find the lowest layer that this region can go on */
2636                 size_t j = layers.size();
2637                 while (j > 0) {
2638                         /* try layer j - 1; it can go on if it overlaps no other region
2639                          * that is already on that layer
2640                          */
2641
2642                         bool overlap = false;
2643                         for (int k = start_division; k <= end_division; ++k) {
2644                                 RegionList::iterator l = layers[j-1][k].begin ();
2645                                 while (l != layers[j-1][k].end()) {
2646                                         if ((*l)->overlap_equivalent (*i)) {
2647                                                 overlap = true;
2648                                                 break;
2649                                         }
2650                                         l++;
2651                                 }
2652
2653                                 if (overlap) {
2654                                         break;
2655                                 }
2656                         }
2657
2658                         if (overlap) {
2659                                 /* overlap, so we must use layer j */
2660                                 break;
2661                         }
2662
2663                         --j;
2664                 }
2665
2666                 if (j == layers.size()) {
2667                         /* we need a new layer for this region */
2668                         layers.push_back (vector<RegionList> (divisions));
2669                 }
2670
2671                 /* put a reference to this region in each of the divisions that it exists in */
2672                 for (int k = start_division; k <= end_division; ++k) {
2673                         layers[j][k].push_back (*i);
2674                 }
2675
2676                 (*i)->set_layer (j);
2677         }
2678
2679         /* It's a little tricky to know when we could avoid calling this; e.g. if we are
2680          * relayering because we just removed the only region on the top layer, nothing will
2681          * appear to have changed, but the StreamView must still sort itself out.  We could
2682          * probably keep a note of the top layer last time we relayered, and check that,
2683          * but premature optimisation &c...
2684          */
2685         notify_layering_changed ();
2686
2687         /* This relayer() may have been called as a result of a region removal, in which
2688          * case we need to setup layering indices to account for the one that has just
2689          * gone away.
2690          */
2691         setup_layering_indices (copy);
2692 }
2693
2694 void
2695 Playlist::raise_region (boost::shared_ptr<Region> region)
2696 {
2697         set_layer (region, region->layer() + 1.5);
2698         relayer ();
2699 }
2700
2701 void
2702 Playlist::lower_region (boost::shared_ptr<Region> region)
2703 {
2704         set_layer (region, region->layer() - 1.5);
2705         relayer ();
2706 }
2707
2708 void
2709 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2710 {
2711         set_layer (region, DBL_MAX);
2712         relayer ();
2713 }
2714
2715 void
2716 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2717 {
2718         set_layer (region, -0.5);
2719         relayer ();
2720 }
2721
2722 void
2723 Playlist::nudge_after (samplepos_t start, samplecnt_t distance, bool forwards)
2724 {
2725         RegionList::iterator i;
2726         bool moved = false;
2727
2728         _nudging = true;
2729
2730         {
2731                 RegionWriteLock rlock (const_cast<Playlist *> (this));
2732
2733                 for (i = regions.begin(); i != regions.end(); ++i) {
2734
2735                         if ((*i)->position() >= start) {
2736
2737                                 samplepos_t new_pos;
2738
2739                                 if (forwards) {
2740
2741                                         if ((*i)->last_sample() > max_samplepos - distance) {
2742                                                 new_pos = max_samplepos - (*i)->length();
2743                                         } else {
2744                                                 new_pos = (*i)->position() + distance;
2745                                         }
2746
2747                                 } else {
2748
2749                                         if ((*i)->position() > distance) {
2750                                                 new_pos = (*i)->position() - distance;
2751                                         } else {
2752                                                 new_pos = 0;
2753                                         }
2754                                 }
2755
2756                                 (*i)->set_position (new_pos);
2757                                 moved = true;
2758                         }
2759                 }
2760         }
2761
2762         if (moved) {
2763                 _nudging = false;
2764                 notify_contents_changed ();
2765         }
2766
2767 }
2768
2769 bool
2770 Playlist::uses_source (boost::shared_ptr<const Source> src, bool shallow) const
2771 {
2772         RegionReadLock rlock (const_cast<Playlist*> (this));
2773
2774         for (set<boost::shared_ptr<Region> >::const_iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
2775                 /* Note: passing the second argument as false can cause at best
2776                  * incredibly deep and time-consuming recursion, and at worst
2777                  * cycles if the user has managed to create cycles of reference
2778                  * between compound regions. We generally only this during
2779                  * cleanup, and @param shallow is passed as true.
2780                  */
2781                 if ((*r)->uses_source (src, shallow)) {
2782                         return true;
2783                 }
2784         }
2785
2786         return false;
2787 }
2788
2789
2790 boost::shared_ptr<Region>
2791 Playlist::find_region (const ID& id) const
2792 {
2793         RegionReadLock rlock (const_cast<Playlist*> (this));
2794
2795         /* searches all regions currently in use by the playlist */
2796
2797         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2798                 if ((*i)->id() == id) {
2799                         return *i;
2800                 }
2801         }
2802
2803         return boost::shared_ptr<Region> ();
2804 }
2805
2806 uint32_t
2807 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2808 {
2809         RegionReadLock rlock (const_cast<Playlist*> (this));
2810         uint32_t cnt = 0;
2811
2812         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2813                 if ((*i) == r) {
2814                         cnt++;
2815                 }
2816         }
2817
2818         RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
2819         for (RegionFactory::CompoundAssociations::iterator it = cassocs.begin(); it != cassocs.end(); ++it) {
2820                 /* check if region is used in a compound */
2821                 if (it->second == r) {
2822                         /* region is referenced as 'original' of a compound */
2823                         ++cnt;
2824                         break;
2825                 }
2826                 if (r->whole_file() && r->max_source_level() > 0) {
2827                         /* region itself ia a compound.
2828                          * the compound regions are not referenced -> check regions inside compound
2829                          */
2830                         const SourceList& sl = r->sources();
2831                         for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
2832                                 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource>(*s);
2833                                 if (!ps) continue;
2834                                 if (ps->playlist()->region_use_count(it->first)) {
2835                                         // break out of both loops
2836                                         return ++cnt;
2837                                 }
2838                         }
2839                 }
2840         }
2841         return cnt;
2842 }
2843
2844 boost::shared_ptr<Region>
2845 Playlist::region_by_id (const ID& id) const
2846 {
2847         /* searches all regions ever added to this playlist */
2848
2849         for (set<boost::shared_ptr<Region> >::const_iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2850                 if ((*i)->id() == id) {
2851                         return *i;
2852                 }
2853         }
2854         return boost::shared_ptr<Region> ();
2855 }
2856
2857 void
2858 Playlist::dump () const
2859 {
2860         boost::shared_ptr<Region> r;
2861
2862         cerr << "Playlist \"" << _name << "\" " << endl
2863              << regions.size() << " regions "
2864              << endl;
2865
2866         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2867                 r = *i;
2868                 cerr << "  " << r->name() << " ["
2869                      << r->start() << "+" << r->length()
2870                      << "] at "
2871                      << r->position()
2872                      << " on layer "
2873                      << r->layer ()
2874                      << endl;
2875         }
2876 }
2877
2878 void
2879 Playlist::set_frozen (bool yn)
2880 {
2881         _frozen = yn;
2882 }
2883
2884 void
2885 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2886 {
2887         bool moved = false;
2888
2889         if (region->locked()) {
2890                 return;
2891         }
2892
2893         _shuffling = true;
2894
2895         {
2896                 RegionWriteLock rlock (const_cast<Playlist*> (this));
2897
2898
2899                 if (dir > 0) {
2900
2901                         RegionList::iterator next;
2902
2903                         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2904                                 if ((*i) == region) {
2905                                         next = i;
2906                                         ++next;
2907
2908                                         if (next != regions.end()) {
2909
2910                                                 if ((*next)->locked()) {
2911                                                         break;
2912                                                 }
2913
2914                                                 samplepos_t new_pos;
2915
2916                                                 if ((*next)->position() != region->last_sample() + 1) {
2917                                                         /* they didn't used to touch, so after shuffle,
2918                                                          * just have them swap positions.
2919                                                          */
2920                                                         new_pos = (*next)->position();
2921                                                 } else {
2922                                                         /* they used to touch, so after shuffle,
2923                                                          * make sure they still do. put the earlier
2924                                                          * region where the later one will end after
2925                                                          * it is moved.
2926                                                          */
2927                                                         new_pos = region->position() + (*next)->length();
2928                                                 }
2929
2930                                                 (*next)->set_position (region->position());
2931                                                 region->set_position (new_pos);
2932
2933                                                 /* avoid a full sort */
2934
2935                                                 regions.erase (i); // removes the region from the list */
2936                                                 next++;
2937                                                 regions.insert (next, region); // adds it back after next
2938
2939                                                 moved = true;
2940                                         }
2941                                         break;
2942                                 }
2943                         }
2944                 } else {
2945
2946                         RegionList::iterator prev = regions.end();
2947
2948                         for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2949                                 if ((*i) == region) {
2950
2951                                         if (prev != regions.end()) {
2952
2953                                                 if ((*prev)->locked()) {
2954                                                         break;
2955                                                 }
2956
2957                                                 samplepos_t new_pos;
2958                                                 if (region->position() != (*prev)->last_sample() + 1) {
2959                                                         /* they didn't used to touch, so after shuffle,
2960                                                          * just have them swap positions.
2961                                                          */
2962                                                         new_pos = region->position();
2963                                                 } else {
2964                                                         /* they used to touch, so after shuffle,
2965                                                          * make sure they still do. put the earlier
2966                                                          * one where the later one will end after
2967                                                          */
2968                                                         new_pos = (*prev)->position() + region->length();
2969                                                 }
2970
2971                                                 region->set_position ((*prev)->position());
2972                                                 (*prev)->set_position (new_pos);
2973
2974                                                 /* avoid a full sort */
2975
2976                                                 regions.erase (i); // remove region
2977                                                 regions.insert (prev, region); // insert region before prev
2978
2979                                                 moved = true;
2980                                         }
2981
2982                                         break;
2983                                 }
2984                         }
2985                 }
2986         }
2987
2988         _shuffling = false;
2989
2990         if (moved) {
2991
2992                 relayer ();
2993                 notify_contents_changed();
2994         }
2995
2996 }
2997
2998 bool
2999 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
3000 {
3001         RegionReadLock rlock (const_cast<Playlist*> (this));
3002
3003         if (regions.size() > 1) {
3004                 return true;
3005         }
3006
3007         return false;
3008 }
3009
3010 void
3011 Playlist::ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
3012 {
3013         ripple_locked (at, distance, exclude);
3014 }
3015
3016 void
3017 Playlist::update_after_tempo_map_change ()
3018 {
3019         RegionWriteLock rlock (const_cast<Playlist*> (this));
3020         RegionList copy (regions.rlist());
3021
3022         freeze ();
3023
3024         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
3025                 (*i)->update_after_tempo_map_change ();
3026         }
3027         /* possibly causes a contents changed notification (flush_notifications()) */
3028         thaw ();
3029 }
3030
3031 void
3032 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
3033 {
3034         RegionReadLock rl (this);
3035         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3036                 s (*i);
3037         }
3038 }
3039
3040 bool
3041 Playlist::has_region_at (samplepos_t const p) const
3042 {
3043         RegionReadLock (const_cast<Playlist *> (this));
3044
3045         RegionList::const_iterator i = regions.begin ();
3046         while (i != regions.end() && !(*i)->covers (p)) {
3047                 ++i;
3048         }
3049
3050         return (i != regions.end());
3051 }
3052
3053 /** Look from a session sample time and find the start time of the next region
3054  *  which is on the top layer of this playlist.
3055  *  @param t Time to look from.
3056  *  @return Position of next top-layered region, or max_samplepos if there isn't one.
3057  */
3058 samplepos_t
3059 Playlist::find_next_top_layer_position (samplepos_t t) const
3060 {
3061         RegionReadLock rlock (const_cast<Playlist *> (this));
3062
3063         layer_t const top = top_layer ();
3064
3065         RegionList copy = regions.rlist ();
3066         copy.sort (RegionSortByPosition ());
3067
3068         for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3069                 if ((*i)->position() >= t && (*i)->layer() == top) {
3070                         return (*i)->position();
3071                 }
3072         }
3073
3074         return max_samplepos;
3075 }
3076
3077 boost::shared_ptr<Region>
3078 Playlist::combine (const RegionList& r)
3079 {
3080         PropertyList plist;
3081         uint32_t channels = 0;
3082         uint32_t layer = 0;
3083         samplepos_t earliest_position = max_samplepos;
3084         vector<TwoRegions> old_and_new_regions;
3085         vector<boost::shared_ptr<Region> > originals;
3086         vector<boost::shared_ptr<Region> > copies;
3087         string parent_name;
3088         string child_name;
3089         uint32_t max_level = 0;
3090
3091         /* find the maximum depth of all the regions we're combining */
3092
3093         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3094                 max_level = max (max_level, (*i)->max_source_level());
3095         }
3096
3097         parent_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, true);
3098         child_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, false);
3099
3100         boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, parent_name, true);
3101
3102         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3103                 earliest_position = min (earliest_position, (*i)->position());
3104         }
3105
3106         /* enable this so that we do not try to create xfades etc. as we add
3107          * regions
3108          */
3109
3110         pl->in_partition = true;
3111
3112         /* sort by position then layer.
3113          * route_time_axis passes 'selected_regions' - which is not sorted.
3114          * here we need the top-most first, then every layer's region sorted by position.
3115          */
3116         RegionList sorted(r);
3117         sorted.sort(RegionSortByLayerAndPosition());
3118
3119         for (RegionList::const_iterator i = sorted.begin(); i != sorted.end(); ++i) {
3120
3121                 /* copy the region */
3122
3123                 boost::shared_ptr<Region> original_region = (*i);
3124                 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
3125
3126                 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
3127                 originals.push_back (original_region);
3128                 copies.push_back (copied_region);
3129
3130                 RegionFactory::add_compound_association (original_region, copied_region);
3131
3132                 /* make position relative to zero */
3133
3134                 pl->add_region (copied_region, original_region->position() - earliest_position);
3135                 copied_region->set_layer (original_region->layer ());
3136
3137                 /* use the maximum number of channels for any region */
3138
3139                 channels = max (channels, original_region->n_channels());
3140
3141                 /* it will go above the layer of the highest existing region */
3142
3143                 layer = max (layer, original_region->layer());
3144         }
3145
3146         pl->in_partition = false;
3147
3148         pre_combine (copies);
3149
3150         /* now create a new PlaylistSource for each channel in the new playlist */
3151
3152         SourceList sources;
3153         pair<samplepos_t,samplepos_t> extent = pl->get_extent();
3154
3155         for (uint32_t chn = 0; chn < channels; ++chn) {
3156                 sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, id(), parent_name, chn, 0, extent.second, false, false));
3157
3158         }
3159
3160         /* now a new whole-file region using the list of sources */
3161
3162         plist.add (Properties::start, 0);
3163         plist.add (Properties::length, extent.second);
3164         plist.add (Properties::name, parent_name);
3165         plist.add (Properties::whole_file, true);
3166
3167         boost::shared_ptr<Region> parent_region = RegionFactory::create (sources, plist, true);
3168
3169         /* now the non-whole-file region that we will actually use in the playlist */
3170
3171         plist.clear ();
3172         plist.add (Properties::start, 0);
3173         plist.add (Properties::length, extent.second);
3174         plist.add (Properties::name, child_name);
3175         plist.add (Properties::layer, layer+1);
3176
3177         boost::shared_ptr<Region> compound_region = RegionFactory::create (parent_region, plist, true);
3178
3179         /* remove all the selected regions from the current playlist */
3180
3181         freeze ();
3182
3183         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3184                 remove_region (*i);
3185         }
3186
3187         /* do type-specific stuff with the originals and the new compound region */
3188
3189         post_combine (originals, compound_region);
3190
3191         /* add the new region at the right location */
3192
3193         add_region (compound_region, earliest_position);
3194
3195         _combine_ops++;
3196
3197         thaw ();
3198
3199         return compound_region;
3200 }
3201
3202 void
3203 Playlist::uncombine (boost::shared_ptr<Region> target)
3204 {
3205         boost::shared_ptr<PlaylistSource> pls;
3206         boost::shared_ptr<const Playlist> pl;
3207         vector<boost::shared_ptr<Region> > originals;
3208         vector<TwoRegions> old_and_new_regions;
3209
3210         // (1) check that its really a compound region
3211
3212         if ((pls = boost::dynamic_pointer_cast<PlaylistSource>(target->source (0))) == 0) {
3213                 return;
3214         }
3215
3216         pl = pls->playlist();
3217
3218         samplepos_t adjusted_start = 0; // gcc isn't smart enough
3219         samplepos_t adjusted_end = 0;   // gcc isn't smart enough
3220
3221         /* the leftmost (earliest) edge of the compound region
3222          * starts at zero in its source, or larger if it
3223          * has been trimmed or content-scrolled.
3224          *
3225          * the rightmost (latest) edge of the compound region
3226          * relative to its source is the starting point plus
3227          * the length of the region.
3228          */
3229
3230         // (2) get all the original regions
3231
3232         const RegionList& rl (pl->region_list_property().rlist());
3233         RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
3234         sampleoffset_t move_offset = 0;
3235
3236         /* there are two possibilities here:
3237            1) the playlist that the playlist source was based on
3238            is us, so just add the originals (which belonged to
3239            us anyway) back in the right place.
3240
3241            2) the playlist that the playlist source was based on
3242            is NOT us, so we need to make copies of each of
3243            the original regions that we find, and add them
3244            instead.
3245         */
3246         bool same_playlist = (pls->original() == id());
3247
3248         for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
3249
3250                 boost::shared_ptr<Region> current (*i);
3251
3252                 RegionFactory::CompoundAssociations::iterator ca = cassocs.find (*i);
3253
3254                 if (ca == cassocs.end()) {
3255                         continue;
3256                 }
3257
3258                 boost::shared_ptr<Region> original (ca->second);
3259                 cassocs.erase(ca);
3260                 bool modified_region;
3261
3262                 if (i == rl.begin()) {
3263                         move_offset = (target->position() - original->position()) - target->start();
3264                         adjusted_start = original->position() + target->start();
3265                         adjusted_end = adjusted_start + target->length();
3266                 }
3267
3268                 if (!same_playlist) {
3269                         samplepos_t pos = original->position();
3270                         /* make a copy, but don't announce it */
3271                         original = RegionFactory::create (original, false);
3272                         /* the pure copy constructor resets position() to zero, so fix that up.  */
3273                         original->set_position (pos);
3274                 }
3275
3276                 /* check to see how the original region (in the
3277                  * playlist before compounding occurred) overlaps
3278                  * with the new state of the compound region.
3279                  */
3280
3281                 original->clear_changes ();
3282                 modified_region = false;
3283
3284                 switch (original->coverage (adjusted_start, adjusted_end)) {
3285                 case Evoral::OverlapNone:
3286                         /* original region does not cover any part
3287                          * of the current state of the compound region
3288                          */
3289                         continue;
3290
3291                 case Evoral::OverlapInternal:
3292                         /* overlap is just a small piece inside the
3293                          * original so trim both ends
3294                          */
3295                         original->trim_to (adjusted_start, adjusted_end - adjusted_start);
3296                         modified_region = true;
3297                         break;
3298
3299                 case Evoral::OverlapExternal:
3300                         /* overlap fully covers original, so leave it as is */
3301                         break;
3302
3303                 case Evoral::OverlapEnd:
3304                         /* overlap starts within but covers end, so trim the front of the region */
3305                         original->trim_front (adjusted_start);
3306                         modified_region = true;
3307                         break;
3308
3309                 case Evoral::OverlapStart:
3310                         /* overlap covers start but ends within, so
3311                          * trim the end of the region.
3312                          */
3313                         original->trim_end (adjusted_end);
3314                         modified_region = true;
3315                         break;
3316                 }
3317
3318                 if (move_offset) {
3319                         /* fix the position to match any movement of the compound region. */
3320                         original->set_position (original->position() + move_offset);
3321                         modified_region = true;
3322                 }
3323
3324                 if (modified_region) {
3325                         _session.add_command (new StatefulDiffCommand (original));
3326                 }
3327
3328                 /* and add to the list of regions waiting to be
3329                  * re-inserted
3330                  */
3331
3332                 originals.push_back (original);
3333                 old_and_new_regions.push_back (TwoRegions (*i, original));
3334         }
3335
3336         pre_uncombine (originals, target);
3337
3338         in_partition = true;
3339         freeze ();
3340
3341         // (3) remove the compound region
3342
3343         remove_region (target);
3344
3345         // (4) add the constituent regions
3346
3347         for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
3348                 add_region ((*i), (*i)->position());
3349                 set_layer((*i), (*i)->layer());
3350                 if (!RegionFactory::region_by_id((*i)->id())) {
3351                         RegionFactory::map_add(*i);
3352                 }
3353         }
3354
3355         in_partition = false;
3356         thaw ();
3357 }
3358
3359 void
3360 Playlist::fade_range (list<AudioRange>& ranges)
3361 {
3362         RegionReadLock rlock (this);
3363         for (list<AudioRange>::iterator r = ranges.begin(); r != ranges.end(); ) {
3364                 list<AudioRange>::iterator tmpr = r;
3365                 ++tmpr;
3366                 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ) {
3367                         RegionList::const_iterator tmpi = i;
3368                         ++tmpi;
3369                         (*i)->fade_range ((*r).start, (*r).end);
3370                         i = tmpi;
3371                 }
3372                 r = tmpr;
3373         }
3374 }
3375
3376 uint32_t
3377 Playlist::max_source_level () const
3378 {
3379         RegionReadLock rlock (const_cast<Playlist *> (this));
3380         uint32_t lvl = 0;
3381
3382         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3383                 lvl = max (lvl, (*i)->max_source_level());
3384         }
3385
3386         return lvl;
3387 }
3388
3389 void
3390 Playlist::set_orig_track_id (const PBD::ID& id)
3391 {
3392         if (shared_with(id)) {
3393                 // Swap 'shared_id' / origin_track_id
3394                 unshare_with (id);
3395                 share_with (_orig_track_id);
3396         }
3397         _orig_track_id = id;
3398 }
3399
3400 void
3401 Playlist::share_with (const PBD::ID& id)
3402 {
3403         if (!shared_with(id)) {
3404                 _shared_with_ids.push_back (id);
3405         }
3406 }
3407
3408 void
3409 Playlist::unshare_with (const PBD::ID& id)
3410 {
3411         list<PBD::ID>::iterator it = _shared_with_ids.begin ();
3412         while (it != _shared_with_ids.end()) {
3413                 if (*it == id) {
3414                         _shared_with_ids.erase (it);
3415                         break;
3416                 }
3417                 ++it;
3418         }
3419 }
3420
3421 bool
3422 Playlist::shared_with (const PBD::ID& id) const
3423 {
3424         bool shared = false;
3425         list<PBD::ID>::const_iterator it = _shared_with_ids.begin ();
3426         while (it != _shared_with_ids.end() && !shared) {
3427                 if (*it == id) {
3428                         shared = true;
3429                 }
3430                 ++it;
3431         }
3432
3433         return shared;
3434 }
3435
3436 void
3437 Playlist::reset_shares ()
3438 {
3439         _shared_with_ids.clear();
3440 }
3441
3442 /** Take a list of ranges, coalesce any that can be coalesced, then call
3443  *  check_crossfades for each one.
3444  */
3445 void
3446 Playlist::coalesce_and_check_crossfades (list<Evoral::Range<samplepos_t> > ranges)
3447 {
3448         /* XXX: it's a shame that this coalesce algorithm also exists in
3449          * TimeSelection::consolidate().
3450          */
3451
3452         /* XXX: xfade: this is implemented in Evoral::RangeList */
3453
3454 restart:
3455         for (list<Evoral::Range<samplepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
3456                 for (list<Evoral::Range<samplepos_t> >::iterator j = ranges.begin(); j != ranges.end(); ++j) {
3457
3458                         if (i == j) {
3459                                 continue;
3460                         }
3461
3462                         // XXX i->from can be > i->to - is this right? coverage() will return OverlapNone in this case
3463                         if (Evoral::coverage (i->from, i->to, j->from, j->to) != Evoral::OverlapNone) {
3464                                 i->from = min (i->from, j->from);
3465                                 i->to = max (i->to, j->to);
3466                                 ranges.erase (j);
3467                                 goto restart;
3468                         }
3469                 }
3470         }
3471 }
3472
3473 void
3474 Playlist::set_capture_insertion_in_progress (bool yn)
3475 {
3476         _capture_insertion_underway = yn;
3477 }