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