Fix a tiny memory-leak when calling vfork
[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         switch (Config->get_region_equivalence()) {
843                  case Exact:
844                          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
845                                  if ((*i)->exact_equivalent (other)) {
846                                          results.push_back (*i);
847                                  }
848                          }
849                          break;
850                  case Enclosed:
851                          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
852                                  if ((*i)->enclosed_equivalent (other)) {
853                                          results.push_back (*i);
854                                  }
855                          }
856                          break;
857                  case Overlap:
858                          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
859                                  if ((*i)->overlap_equivalent (other)) {
860                                          results.push_back (*i);
861                                  }
862                          }
863                          break;
864         }
865 }
866
867 void
868 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
869 {
870         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
871
872                 if ((*i) && (*i)->region_list_equivalent (other)) {
873                         results.push_back (*i);
874                 }
875         }
876 }
877
878 void
879 Playlist::get_source_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
880 {
881         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
882
883                 if ((*i) && (*i)->any_source_equivalent (other)) {
884                         results.push_back (*i);
885                 }
886         }
887 }
888
889 void
890 Playlist::partition (samplepos_t start, samplepos_t end, bool cut)
891 {
892         RegionList thawlist;
893         {
894                 RegionWriteLock lock(this);
895                 partition_internal (start, end, cut, thawlist);
896         }
897
898         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
899                 (*i)->resume_property_changes ();
900         }
901 }
902
903 /* If a MIDI region is locked to musical-time, Properties::start is ignored
904  * and _start is overwritten using Properties::start_beats in
905  * add_region_internal() -> Region::set_position() -> MidiRegion::set_position_internal()
906  */
907 static void maybe_add_start_beats (TempoMap const& tm, PropertyList& plist, boost::shared_ptr<Region> r, samplepos_t start, samplepos_t end)
908 {
909         boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(r);
910         if (!mr) {
911                 return;
912         }
913         double delta_beats = tm.quarter_notes_between_samples (start, end);
914         plist.add (Properties::start_beats, mr->start_beats () + delta_beats);
915 }
916
917 /** Go through each region on the playlist and cut them at start and end, removing the section between
918  *  start and end if cutting == true.  Regions that lie entirely within start and end are always
919  *  removed.
920  */
921
922 void
923 Playlist::partition_internal (samplepos_t start, samplepos_t end, bool cutting, RegionList& thawlist)
924 {
925         RegionList new_regions;
926
927         {
928
929                 boost::shared_ptr<Region> region;
930                 boost::shared_ptr<Region> current;
931                 string new_name;
932                 RegionList::iterator tmp;
933                 Evoral::OverlapType overlap;
934                 samplepos_t pos1, pos2, pos3, pos4;
935
936                 in_partition = true;
937
938                 /* need to work from a copy, because otherwise the regions we add during the process
939                    get operated on as well.
940                 */
941
942                 RegionList copy = regions.rlist();
943
944                 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
945
946                         tmp = i;
947                         ++tmp;
948
949                         current = *i;
950
951                         if (current->first_sample() >= start && current->last_sample() < end) {
952
953                                 if (cutting) {
954                                         remove_region_internal (current);
955                                 }
956
957                                 continue;
958                         }
959
960                         /* coverage will return OverlapStart if the start coincides
961                            with the end point. we do not partition such a region,
962                            so catch this special case.
963                         */
964
965                         if (current->first_sample() >= end) {
966                                 continue;
967                         }
968
969                         if ((overlap = current->coverage (start, end)) == Evoral::OverlapNone) {
970                                 continue;
971                         }
972
973                         pos1 = current->position();
974                         pos2 = start;
975                         pos3 = end;
976                         pos4 = current->last_sample();
977
978                         if (overlap == Evoral::OverlapInternal) {
979                                 /* split: we need 3 new regions, the front, middle and end.
980                                    cut:   we need 2 regions, the front and end.
981                                 */
982
983                                 /*
984                                   start                 end
985                                   ---------------*************************------------
986                                   P1  P2              P3  P4
987                                   SPLIT:
988                                   ---------------*****++++++++++++++++====------------
989                                   CUT
990                                   ---------------*****----------------====------------
991
992                                 */
993
994                                 if (!cutting) {
995                                         /* "middle" ++++++ */
996
997                                         RegionFactory::region_name (new_name, current->name(), false);
998
999                                         PropertyList plist;
1000
1001                                         plist.add (Properties::start, current->start() + (pos2 - pos1));
1002                                         plist.add (Properties::length, pos3 - pos2);
1003                                         plist.add (Properties::name, new_name);
1004                                         plist.add (Properties::layer, current->layer ());
1005                                         plist.add (Properties::layering_index, current->layering_index ());
1006                                         plist.add (Properties::automatic, true);
1007                                         plist.add (Properties::left_of_split, true);
1008                                         plist.add (Properties::right_of_split, true);
1009                                         maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start() + (pos2 - pos1));
1010
1011                                         /* see note in :_split_region()
1012                                          * for MusicSample is needed to offset region-gain
1013                                          */
1014                                         region = RegionFactory::create (current, MusicSample (pos2 - pos1, 0), plist);
1015                                         add_region_internal (region, start);
1016                                         new_regions.push_back (region);
1017                                 }
1018
1019                                 /* "end" ====== */
1020
1021                                 RegionFactory::region_name (new_name, current->name(), false);
1022
1023                                 PropertyList plist;
1024
1025                                 plist.add (Properties::start, current->start() + (pos3 - pos1));
1026                                 plist.add (Properties::length, pos4 - pos3);
1027                                 plist.add (Properties::name, new_name);
1028                                 plist.add (Properties::layer, current->layer ());
1029                                 plist.add (Properties::layering_index, current->layering_index ());
1030                                 plist.add (Properties::automatic, true);
1031                                 plist.add (Properties::right_of_split, true);
1032                                 maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start() + (pos3 - pos1));
1033
1034                                 region = RegionFactory::create (current, MusicSample (pos3 - pos1, 0), plist);
1035
1036                                 add_region_internal (region, end);
1037                                 new_regions.push_back (region);
1038
1039                                 /* "front" ***** */
1040
1041                                 current->clear_changes ();
1042                                 current->suspend_property_changes ();
1043                                 thawlist.push_back (current);
1044                                 current->cut_end (pos2 - 1);
1045
1046                         } else if (overlap == Evoral::OverlapEnd) {
1047
1048                                 /*
1049                                   start           end
1050                                   ---------------*************************------------
1051                                   P1           P2         P4   P3
1052                                   SPLIT:
1053                                   ---------------**************+++++++++++------------
1054                                   CUT:
1055                                   ---------------**************-----------------------
1056                                 */
1057
1058                                 if (!cutting) {
1059
1060                                         /* end +++++ */
1061
1062                                         RegionFactory::region_name (new_name, current->name(), false);
1063
1064                                         PropertyList plist;
1065
1066                                         plist.add (Properties::start, current->start() + (pos2 - pos1));
1067                                         plist.add (Properties::length, pos4 - pos2);
1068                                         plist.add (Properties::name, new_name);
1069                                         plist.add (Properties::layer, current->layer ());
1070                                         plist.add (Properties::layering_index, current->layering_index ());
1071                                         plist.add (Properties::automatic, true);
1072                                         plist.add (Properties::left_of_split, true);
1073                                         maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start() + (pos2 - pos1));
1074
1075                                         region = RegionFactory::create (current, MusicSample(pos2 - pos1, 0), plist);
1076
1077                                         add_region_internal (region, start);
1078                                         new_regions.push_back (region);
1079                                 }
1080
1081                                 /* front ****** */
1082
1083                                 current->clear_changes ();
1084                                 current->suspend_property_changes ();
1085                                 thawlist.push_back (current);
1086                                 current->cut_end (pos2 - 1);
1087
1088                         } else if (overlap == Evoral::OverlapStart) {
1089
1090                                 /* split: we need 2 regions: the front and the end.
1091                                    cut: just trim current to skip the cut area
1092                                 */
1093
1094                                 /*
1095                                   start           end
1096                                   ---------------*************************------------
1097                                   P2          P1 P3                   P4
1098
1099                                   SPLIT:
1100                                   ---------------****+++++++++++++++++++++------------
1101                                   CUT:
1102                                   -------------------*********************------------
1103
1104                                 */
1105
1106                                 if (!cutting) {
1107                                         /* front **** */
1108                                         RegionFactory::region_name (new_name, current->name(), false);
1109
1110                                         PropertyList plist;
1111
1112                                         plist.add (Properties::start, current->start());
1113                                         plist.add (Properties::length, pos3 - pos1);
1114                                         plist.add (Properties::name, new_name);
1115                                         plist.add (Properties::layer, current->layer ());
1116                                         plist.add (Properties::layering_index, current->layering_index ());
1117                                         plist.add (Properties::automatic, true);
1118                                         plist.add (Properties::right_of_split, true);
1119                                         maybe_add_start_beats (_session.tempo_map(), plist, current, current->start(), current->start());
1120
1121                                         region = RegionFactory::create (current, plist);
1122
1123                                         add_region_internal (region, pos1);
1124                                         new_regions.push_back (region);
1125                                 }
1126
1127                                 /* end */
1128
1129                                 current->clear_changes ();
1130                                 current->suspend_property_changes ();
1131                                 thawlist.push_back (current);
1132                                 current->trim_front (pos3);
1133                         } else if (overlap == Evoral::OverlapExternal) {
1134
1135                                 /* split: no split required.
1136                                    cut: remove the region.
1137                                 */
1138
1139                                 /*
1140                                   start                                      end
1141                                   ---------------*************************------------
1142                                   P2          P1 P3                   P4
1143
1144                                   SPLIT:
1145                                   ---------------*************************------------
1146                                   CUT:
1147                                   ----------------------------------------------------
1148
1149                                 */
1150
1151                                 if (cutting) {
1152                                         remove_region_internal (current);
1153                                 }
1154
1155                                 new_regions.push_back (current);
1156                         }
1157                 }
1158
1159                 in_partition = false;
1160         }
1161
1162         //keep track of any dead space at end (for pasting into Ripple or Splice mode)
1163         samplepos_t wanted_length = end-start;
1164         _end_space = wanted_length - _get_extent().second - _get_extent().first;
1165 }
1166
1167 boost::shared_ptr<Playlist>
1168 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t, samplecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1169 {
1170         boost::shared_ptr<Playlist> ret;
1171         boost::shared_ptr<Playlist> pl;
1172         samplepos_t start;
1173
1174         if (ranges.empty()) {
1175                 return boost::shared_ptr<Playlist>();
1176         }
1177
1178         start = ranges.front().start;
1179
1180         for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1181
1182                 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1183
1184                 if (i == ranges.begin()) {
1185                         ret = pl;
1186                 } else {
1187
1188                         /* paste the next section into the nascent playlist,
1189                            offset to reflect the start of the first range we
1190                            chopped.
1191                         */
1192
1193                         ret->paste (pl, (*i).start - start, 1.0f, 0);
1194                 }
1195         }
1196
1197         return ret;
1198 }
1199
1200 boost::shared_ptr<Playlist>
1201 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1202 {
1203         boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t,samplecnt_t,bool) = &Playlist::cut;
1204         return cut_copy (pmf, ranges, result_is_hidden);
1205 }
1206
1207 boost::shared_ptr<Playlist>
1208 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1209 {
1210         boost::shared_ptr<Playlist> (Playlist::*pmf)(samplepos_t,samplecnt_t,bool) = &Playlist::copy;
1211         return cut_copy (pmf, ranges, result_is_hidden);
1212 }
1213
1214 boost::shared_ptr<Playlist>
1215 Playlist::cut (samplepos_t start, samplecnt_t cnt, bool result_is_hidden)
1216 {
1217         boost::shared_ptr<Playlist> the_copy;
1218         RegionList thawlist;
1219         char buf[32];
1220
1221         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1222         string new_name = _name;
1223         new_name += '.';
1224         new_name += buf;
1225
1226         if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1227                 return boost::shared_ptr<Playlist>();
1228         }
1229
1230         {
1231                 RegionWriteLock rlock (this);
1232                 partition_internal (start, start+cnt-1, true, thawlist);
1233         }
1234
1235         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1236                 (*i)->resume_property_changes();
1237         }
1238
1239         return the_copy;
1240 }
1241
1242 boost::shared_ptr<Playlist>
1243 Playlist::copy (samplepos_t start, samplecnt_t cnt, bool result_is_hidden)
1244 {
1245         char buf[32];
1246
1247         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1248         string new_name = _name;
1249         new_name += '.';
1250         new_name += buf;
1251
1252         // 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... )
1253
1254         return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1255 }
1256
1257 int
1258 Playlist::paste (boost::shared_ptr<Playlist> other, samplepos_t position, float times, const int32_t sub_num)
1259 {
1260         times = fabs (times);
1261
1262         {
1263                 RegionReadLock rl2 (other.get());
1264
1265                 int itimes = (int) floor (times);
1266                 samplepos_t pos = position;
1267                 samplecnt_t const shift = other->_get_extent().second;
1268                 layer_t top = top_layer ();
1269
1270                 {
1271                         RegionWriteLock rl1 (this);
1272                         while (itimes--) {
1273                                 for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1274                                         boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1275
1276                                         /* put these new regions on top of all existing ones, but preserve
1277                                            the ordering they had in the original playlist.
1278                                         */
1279
1280                                         add_region_internal (copy_of_region, (*i)->position() + pos, sub_num);
1281                                         set_layer (copy_of_region, copy_of_region->layer() + top);
1282                                 }
1283                                 pos += shift;
1284                         }
1285                 }
1286         }
1287
1288         return 0;
1289 }
1290
1291
1292 void
1293 Playlist::duplicate (boost::shared_ptr<Region> region, samplepos_t position, float times)
1294 {
1295         duplicate(region, position, region->length(), times);
1296 }
1297
1298 /** @param gap from the beginning of the region to the next beginning */
1299 void
1300 Playlist::duplicate (boost::shared_ptr<Region> region, samplepos_t position, samplecnt_t gap, float times)
1301 {
1302         times = fabs (times);
1303
1304         RegionWriteLock rl (this);
1305         int itimes = (int) floor (times);
1306
1307         while (itimes--) {
1308                 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1309                 add_region_internal (copy, position);
1310                 set_layer (copy, DBL_MAX);
1311                 position += gap;
1312         }
1313
1314         if (floor (times) != times) {
1315                 samplecnt_t length = (samplecnt_t) floor (region->length() * (times - floor (times)));
1316                 string name;
1317                 RegionFactory::region_name (name, region->name(), false);
1318
1319                 {
1320                         PropertyList plist;
1321
1322                         plist.add (Properties::start, region->start());
1323                         plist.add (Properties::length, length);
1324                         plist.add (Properties::name, name);
1325
1326                         boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1327                         add_region_internal (sub, position);
1328                         set_layer (sub, DBL_MAX);
1329                 }
1330         }
1331 }
1332
1333 /** @param gap from the beginning of the region to the next beginning */
1334 /** @param end the first sample that does _not_ contain a duplicated sample */
1335 void
1336 Playlist::duplicate_until (boost::shared_ptr<Region> region, samplepos_t position, samplecnt_t gap, samplepos_t end)
1337 {
1338          RegionWriteLock rl (this);
1339
1340          while (position + region->length() - 1 < end) {
1341                  boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1342                  add_region_internal (copy, position);
1343                  set_layer (copy, DBL_MAX);
1344                  position += gap;
1345          }
1346
1347          if (position < end) {
1348                  samplecnt_t length = min (region->length(), end - position);
1349                  string name;
1350                  RegionFactory::region_name (name, region->name(), false);
1351
1352                  {
1353                          PropertyList plist;
1354
1355                          plist.add (Properties::start, region->start());
1356                          plist.add (Properties::length, length);
1357                          plist.add (Properties::name, name);
1358
1359                          boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1360                          add_region_internal (sub, position);
1361                          set_layer (sub, DBL_MAX);
1362                  }
1363          }
1364 }
1365
1366 void
1367 Playlist::duplicate_range (AudioRange& range, float times)
1368 {
1369         boost::shared_ptr<Playlist> pl = copy (range.start, range.length(), true);
1370         samplecnt_t offset = range.end - range.start;
1371         paste (pl, range.start + offset, times, 0);
1372 }
1373
1374 void
1375 Playlist::duplicate_ranges (std::list<AudioRange>& ranges, float times)
1376 {
1377         if (ranges.empty()) {
1378                 return;
1379         }
1380
1381         samplepos_t min_pos = max_samplepos;
1382         samplepos_t max_pos = 0;
1383
1384         for (std::list<AudioRange>::const_iterator i = ranges.begin();
1385              i != ranges.end();
1386              ++i) {
1387                 min_pos = min (min_pos, (*i).start);
1388                 max_pos = max (max_pos, (*i).end);
1389         }
1390
1391         samplecnt_t offset = max_pos - min_pos;
1392
1393         int count = 1;
1394         int itimes = (int) floor (times);
1395         while (itimes--) {
1396                 for (list<AudioRange>::iterator i = ranges.begin (); i != ranges.end (); ++i) {
1397                         boost::shared_ptr<Playlist> pl = copy ((*i).start, (*i).length (), true);
1398                         paste (pl, (*i).start + (offset * count), 1.0f, 0);
1399                 }
1400                 ++count;
1401         }
1402 }
1403
1404  void
1405  Playlist::shift (samplepos_t at, sampleoffset_t distance, bool move_intersected, bool ignore_music_glue)
1406  {
1407          RegionWriteLock rlock (this);
1408          RegionList copy (regions.rlist());
1409          RegionList fixup;
1410
1411          for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1412
1413                  if ((*r)->last_sample() < at) {
1414                          /* too early */
1415                          continue;
1416                  }
1417
1418                  if (at > (*r)->first_sample() && at < (*r)->last_sample()) {
1419                          /* intersected region */
1420                          if (!move_intersected) {
1421                                  continue;
1422                          }
1423                  }
1424
1425                  /* do not move regions glued to music time - that
1426                     has to be done separately.
1427                  */
1428
1429                  if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1430                          fixup.push_back (*r);
1431                          continue;
1432                  }
1433
1434                  (*r)->set_position ((*r)->position() + distance);
1435          }
1436
1437          /* XXX: may not be necessary; Region::post_set should do this, I think */
1438          for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1439                  (*r)->recompute_position_from_lock_style (0);
1440          }
1441  }
1442
1443  void
1444  Playlist::split (const MusicSample& at)
1445  {
1446          RegionWriteLock rlock (this);
1447          RegionList copy (regions.rlist());
1448
1449          /* use a copy since this operation can modify the region list
1450           */
1451
1452          for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1453                  _split_region (*r, at);
1454          }
1455  }
1456
1457  void
1458  Playlist::split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position)
1459  {
1460          RegionWriteLock rl (this);
1461          _split_region (region, playlist_position);
1462  }
1463
1464  void
1465  Playlist::_split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position)
1466  {
1467          if (!region->covers (playlist_position.sample)) {
1468                  return;
1469          }
1470
1471          if (region->position() == playlist_position.sample ||
1472              region->last_sample() == playlist_position.sample) {
1473                  return;
1474          }
1475
1476          boost::shared_ptr<Region> left;
1477          boost::shared_ptr<Region> right;
1478
1479          MusicSample before (playlist_position.sample - region->position(), playlist_position.division);
1480          MusicSample after (region->length() - before.sample, 0);
1481          string before_name;
1482          string after_name;
1483
1484          /* split doesn't change anything about length, so don't try to splice */
1485
1486          bool old_sp = _splicing;
1487          _splicing = true;
1488
1489          RegionFactory::region_name (before_name, region->name(), false);
1490
1491          {
1492                  PropertyList plist;
1493
1494                  plist.add (Properties::length, before.sample);
1495                  plist.add (Properties::name, before_name);
1496                  plist.add (Properties::left_of_split, true);
1497                  plist.add (Properties::layering_index, region->layering_index ());
1498                  plist.add (Properties::layer, region->layer ());
1499
1500                  /* note: we must use the version of ::create with an offset here,
1501                     since it supplies that offset to the Region constructor, which
1502                     is necessary to get audio region gain envelopes right.
1503                  */
1504                  left = RegionFactory::create (region, MusicSample (0, 0), plist, true);
1505          }
1506
1507          RegionFactory::region_name (after_name, region->name(), false);
1508
1509          {
1510                  PropertyList plist;
1511
1512                  plist.add (Properties::length, after.sample);
1513                  plist.add (Properties::name, after_name);
1514                  plist.add (Properties::right_of_split, true);
1515                  plist.add (Properties::layering_index, region->layering_index ());
1516                  plist.add (Properties::layer, region->layer ());
1517
1518                  /* same note as above */
1519                  right = RegionFactory::create (region, before, plist, true);
1520          }
1521
1522          add_region_internal (left, region->position(), 0);
1523          add_region_internal (right, region->position() + before.sample, before.division);
1524
1525          remove_region_internal (region);
1526
1527          _splicing = old_sp;
1528  }
1529
1530 void
1531 Playlist::AddToSoloSelectedList(const Region* r)
1532 {
1533         _soloSelectedRegions.insert (r);        
1534 }
1535
1536
1537 void
1538 Playlist::RemoveFromSoloSelectedList(const Region* r)
1539 {
1540         _soloSelectedRegions.erase (r); 
1541 }
1542
1543
1544 bool
1545 Playlist::SoloSelectedListIncludes(const Region* r)
1546 {
1547         std::set<const Region*>::iterator i = _soloSelectedRegions.find(r);
1548
1549         return ( i != _soloSelectedRegions.end() );
1550 }
1551
1552 bool
1553 Playlist::SoloSelectedActive()
1554 {
1555         return !_soloSelectedRegions.empty();
1556 }
1557
1558
1559  void
1560  Playlist::possibly_splice (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1561  {
1562          if (_splicing || in_set_state) {
1563                  /* don't respond to splicing moves or state setting */
1564                  return;
1565          }
1566
1567          if (_edit_mode == Splice) {
1568                  splice_locked (at, distance, exclude);
1569          }
1570  }
1571
1572  void
1573  Playlist::possibly_splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1574  {
1575          if (_splicing || in_set_state) {
1576                  /* don't respond to splicing moves or state setting */
1577                  return;
1578          }
1579
1580          if (_edit_mode == Splice) {
1581                  splice_unlocked (at, distance, exclude);
1582          }
1583  }
1584
1585  void
1586  Playlist::splice_locked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1587  {
1588          {
1589                  RegionWriteLock rl (this);
1590                  core_splice (at, distance, exclude);
1591          }
1592  }
1593
1594  void
1595  Playlist::splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1596  {
1597          core_splice (at, distance, exclude);
1598  }
1599
1600  void
1601  Playlist::core_splice (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
1602  {
1603          _splicing = true;
1604
1605          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1606
1607                  if (exclude && (*i) == exclude) {
1608                          continue;
1609                  }
1610
1611                  if ((*i)->position() >= at) {
1612                          samplepos_t new_pos = (*i)->position() + distance;
1613                          if (new_pos < 0) {
1614                                  new_pos = 0;
1615                          } else if (new_pos >= max_samplepos - (*i)->length()) {
1616                                  new_pos = max_samplepos - (*i)->length();
1617                          }
1618
1619                          (*i)->set_position (new_pos);
1620                  }
1621          }
1622
1623          _splicing = false;
1624
1625          notify_contents_changed ();
1626 }
1627
1628 void
1629 Playlist::ripple_locked (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1630 {
1631         {
1632                 RegionWriteLock rl (this);
1633                 core_ripple (at, distance, exclude);
1634         }
1635 }
1636
1637 void
1638 Playlist::ripple_unlocked (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1639 {
1640         core_ripple (at, distance, exclude);
1641 }
1642
1643 void
1644 Playlist::core_ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
1645 {
1646         if (distance == 0) {
1647                 return;
1648         }
1649
1650         _rippling = true;
1651         RegionListProperty copy = regions;
1652         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1653                 assert (i != copy.end());
1654
1655                 if (exclude) {
1656                         if (std::find(exclude->begin(), exclude->end(), (*i)) != exclude->end()) {
1657                                 continue;
1658                         }
1659                 }
1660
1661                 if ((*i)->position() >= at) {
1662                         samplepos_t new_pos = (*i)->position() + distance;
1663                         samplepos_t limit = max_samplepos - (*i)->length();
1664                         if (new_pos < 0) {
1665                                 new_pos = 0;
1666                         } else if (new_pos >= limit ) {
1667                                 new_pos = limit;
1668                         }
1669
1670                         (*i)->set_position (new_pos);
1671                 }
1672         }
1673
1674         _rippling = false;
1675         notify_contents_changed ();
1676 }
1677
1678
1679 void
1680 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1681 {
1682          if (in_set_state || _splicing || _rippling || _nudging || _shuffling) {
1683                  return;
1684          }
1685
1686          if (what_changed.contains (Properties::position)) {
1687
1688                  /* remove it from the list then add it back in
1689                     the right place again.
1690                  */
1691
1692                  RegionSortByPosition cmp;
1693
1694                  RegionList::iterator i = find (regions.begin(), regions.end(), region);
1695
1696                  if (i == regions.end()) {
1697                          /* the region bounds are being modified but its not currently
1698                             in the region list. we will use its bounds correctly when/if
1699                             it is added
1700                          */
1701                          return;
1702                  }
1703
1704                  regions.erase (i);
1705                  regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1706          }
1707
1708          if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1709
1710                  sampleoffset_t delta = 0;
1711
1712                  if (what_changed.contains (Properties::position)) {
1713                          delta = region->position() - region->last_position();
1714                  }
1715
1716                  if (what_changed.contains (Properties::length)) {
1717                          delta += region->length() - region->last_length();
1718                  }
1719
1720                  if (delta) {
1721                          possibly_splice (region->last_position() + region->last_length(), delta, region);
1722                  }
1723
1724                  if (holding_state ()) {
1725                          pending_bounds.push_back (region);
1726                  } else {
1727                          notify_contents_changed ();
1728                          relayer ();
1729                          list<Evoral::Range<samplepos_t> > xf;
1730                          xf.push_back (Evoral::Range<samplepos_t> (region->last_range()));
1731                          xf.push_back (Evoral::Range<samplepos_t> (region->range()));
1732                          coalesce_and_check_crossfades (xf);
1733                  }
1734          }
1735  }
1736
1737  void
1738  Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1739  {
1740          boost::shared_ptr<Region> region (weak_region.lock());
1741
1742          if (!region) {
1743                  return;
1744          }
1745
1746          /* this makes a virtual call to the right kind of playlist ... */
1747
1748          region_changed (what_changed, region);
1749  }
1750
1751  bool
1752  Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1753  {
1754          PropertyChange our_interests;
1755          PropertyChange bounds;
1756          PropertyChange pos_and_length;
1757          bool save = false;
1758
1759          if (in_set_state || in_flush) {
1760                  return false;
1761          }
1762
1763          our_interests.add (Properties::muted);
1764          our_interests.add (Properties::layer);
1765          our_interests.add (Properties::opaque);
1766
1767          bounds.add (Properties::start);
1768          bounds.add (Properties::position);
1769          bounds.add (Properties::length);
1770
1771          pos_and_length.add (Properties::position);
1772          pos_and_length.add (Properties::length);
1773
1774          if (what_changed.contains (bounds)) {
1775                  region_bounds_changed (what_changed, region);
1776                  save = !(_splicing || _nudging);
1777          }
1778
1779          if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1780                  notify_region_moved (region);
1781          } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1782                  notify_region_end_trimmed (region);
1783          } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1784                  notify_region_start_trimmed (region);
1785          }
1786
1787          /* don't notify about layer changes, since we are the only object that can initiate
1788             them, and we notify in ::relayer()
1789          */
1790
1791          if (what_changed.contains (our_interests)) {
1792                  save = true;
1793          }
1794
1795          mark_session_dirty ();
1796
1797          return save;
1798  }
1799
1800  void
1801  Playlist::drop_regions ()
1802  {
1803          RegionWriteLock rl (this);
1804          regions.clear ();
1805          all_regions.clear ();
1806  }
1807
1808  void
1809  Playlist::sync_all_regions_with_regions ()
1810  {
1811          RegionWriteLock rl (this);
1812
1813          all_regions.clear ();
1814
1815          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1816                  all_regions.insert (*i);
1817          }
1818  }
1819
1820  void
1821  Playlist::clear (bool with_signals)
1822  {
1823          {
1824                  RegionWriteLock rl (this);
1825
1826                  region_state_changed_connections.drop_connections ();
1827                  region_drop_references_connections.drop_connections ();
1828
1829                  for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1830                          pending_removes.insert (*i);
1831                  }
1832
1833                  regions.clear ();
1834
1835                  for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1836                          remove_dependents (*s);
1837                  }
1838          }
1839
1840          if (with_signals) {
1841
1842                  for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1843                          RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1844                  }
1845
1846                  pending_removes.clear ();
1847                  pending_contents_change = false;
1848                  ContentsChanged ();
1849          }
1850
1851  }
1852
1853  /* *********************************************************************
1854   FINDING THINGS
1855   **********************************************************************/
1856
1857 boost::shared_ptr<RegionList>
1858 Playlist::region_list()
1859 {
1860         RegionReadLock rlock (this);
1861         boost::shared_ptr<RegionList> rlist (new RegionList (regions.rlist ()));
1862         return rlist;
1863 }
1864
1865 void
1866 Playlist::deep_sources (std::set<boost::shared_ptr<Source> >& sources) const
1867 {
1868         RegionReadLock rlock (const_cast<Playlist*>(this));
1869
1870         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1871                 (*i)->deep_sources (sources);
1872         }
1873 }
1874
1875 boost::shared_ptr<RegionList>
1876 Playlist::regions_at (samplepos_t sample)
1877 {
1878         RegionReadLock rlock (this);
1879         return find_regions_at (sample);
1880 }
1881
1882  uint32_t
1883  Playlist::count_regions_at (samplepos_t sample) const
1884  {
1885          RegionReadLock rlock (const_cast<Playlist*>(this));
1886          uint32_t cnt = 0;
1887
1888          for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1889                  if ((*i)->covers (sample)) {
1890                          cnt++;
1891                  }
1892          }
1893
1894          return cnt;
1895  }
1896
1897  boost::shared_ptr<Region>
1898  Playlist::top_region_at (samplepos_t sample)
1899
1900  {
1901          RegionReadLock rlock (this);
1902          boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1903          boost::shared_ptr<Region> region;
1904
1905          if (rlist->size()) {
1906                  RegionSortByLayer cmp;
1907                  rlist->sort (cmp);
1908                  region = rlist->back();
1909          }
1910
1911          return region;
1912  }
1913
1914  boost::shared_ptr<Region>
1915  Playlist::top_unmuted_region_at (samplepos_t sample)
1916
1917  {
1918          RegionReadLock rlock (this);
1919          boost::shared_ptr<RegionList> rlist = find_regions_at (sample);
1920
1921          for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1922
1923                  RegionList::iterator tmp = i;
1924
1925                  ++tmp;
1926
1927                  if ((*i)->muted()) {
1928                          rlist->erase (i);
1929                  }
1930
1931                  i = tmp;
1932          }
1933
1934          boost::shared_ptr<Region> region;
1935
1936          if (rlist->size()) {
1937                  RegionSortByLayer cmp;
1938                  rlist->sort (cmp);
1939                  region = rlist->back();
1940          }
1941
1942          return region;
1943  }
1944
1945 boost::shared_ptr<RegionList>
1946 Playlist::find_regions_at (samplepos_t sample)
1947 {
1948         /* Caller must hold lock */
1949
1950         boost::shared_ptr<RegionList> rlist (new RegionList);
1951
1952         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1953                 if ((*i)->covers (sample)) {
1954                         rlist->push_back (*i);
1955                 }
1956         }
1957
1958         return rlist;
1959 }
1960
1961 boost::shared_ptr<RegionList>
1962 Playlist::regions_with_start_within (Evoral::Range<samplepos_t> range)
1963 {
1964         RegionReadLock rlock (this);
1965         boost::shared_ptr<RegionList> rlist (new RegionList);
1966
1967         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1968                 if ((*i)->first_sample() >= range.from && (*i)->first_sample() <= range.to) {
1969                         rlist->push_back (*i);
1970                 }
1971         }
1972
1973         return rlist;
1974 }
1975
1976 boost::shared_ptr<RegionList>
1977 Playlist::regions_with_end_within (Evoral::Range<samplepos_t> range)
1978 {
1979         RegionReadLock rlock (this);
1980         boost::shared_ptr<RegionList> rlist (new RegionList);
1981
1982         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1983                 if ((*i)->last_sample() >= range.from && (*i)->last_sample() <= range.to) {
1984                         rlist->push_back (*i);
1985                 }
1986         }
1987
1988         return rlist;
1989 }
1990
1991 /** @param start Range start.
1992  *  @param end Range end.
1993  *  @return regions which have some part within this range.
1994  */
1995 boost::shared_ptr<RegionList>
1996 Playlist::regions_touched (samplepos_t start, samplepos_t end)
1997 {
1998         RegionReadLock rlock (this);
1999         return regions_touched_locked (start, end);
2000 }
2001
2002 boost::shared_ptr<RegionList>
2003 Playlist::regions_touched_locked (samplepos_t start, samplepos_t end)
2004 {
2005         boost::shared_ptr<RegionList> rlist (new RegionList);
2006
2007         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2008                 if ((*i)->coverage (start, end) != Evoral::OverlapNone) {
2009                         rlist->push_back (*i);
2010                 }
2011         }
2012
2013         return rlist;
2014 }
2015
2016 samplepos_t
2017 Playlist::find_next_transient (samplepos_t from, int dir)
2018 {
2019         RegionReadLock rlock (this);
2020         AnalysisFeatureList points;
2021         AnalysisFeatureList these_points;
2022
2023         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2024                 if (dir > 0) {
2025                         if ((*i)->last_sample() < from) {
2026                                 continue;
2027                         }
2028                 } else {
2029                         if ((*i)->first_sample() > from) {
2030                                 continue;
2031                         }
2032                 }
2033
2034                 (*i)->get_transients (these_points);
2035
2036                 /* add first sample, just, err, because */
2037
2038                 these_points.push_back ((*i)->first_sample());
2039
2040                 points.insert (points.end(), these_points.begin(), these_points.end());
2041                 these_points.clear ();
2042         }
2043
2044         if (points.empty()) {
2045                 return -1;
2046         }
2047
2048         TransientDetector::cleanup_transients (points, _session.sample_rate(), 3.0);
2049         bool reached = false;
2050
2051         if (dir > 0) {
2052                 for (AnalysisFeatureList::const_iterator x = points.begin(); x != points.end(); ++x) {
2053                         if ((*x) >= from) {
2054                                 reached = true;
2055                         }
2056
2057                         if (reached && (*x) > from) {
2058                                 return *x;
2059                         }
2060                 }
2061         } else {
2062                 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
2063                         if ((*x) <= from) {
2064                                 reached = true;
2065                         }
2066
2067                         if (reached && (*x) < from) {
2068                                 return *x;
2069                         }
2070                 }
2071         }
2072
2073         return -1;
2074 }
2075
2076 boost::shared_ptr<Region>
2077 Playlist::find_next_region (samplepos_t sample, RegionPoint point, int dir)
2078 {
2079         RegionReadLock rlock (this);
2080         boost::shared_ptr<Region> ret;
2081         samplepos_t closest = max_samplepos;
2082
2083         bool end_iter = false;
2084
2085         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2086
2087                 if(end_iter) break;
2088
2089                 sampleoffset_t distance;
2090                 boost::shared_ptr<Region> r = (*i);
2091                 samplepos_t pos = 0;
2092
2093                 switch (point) {
2094                 case Start:
2095                         pos = r->first_sample ();
2096                         break;
2097                 case End:
2098                         pos = r->last_sample ();
2099                         break;
2100                 case SyncPoint:
2101                         pos = r->sync_position ();
2102                         break;
2103                 }
2104
2105                 switch (dir) {
2106                 case 1: /* forwards */
2107
2108                         if (pos > sample) {
2109                                 if ((distance = pos - sample) < closest) {
2110                                         closest = distance;
2111                                         ret = r;
2112                                         end_iter = true;
2113                                 }
2114                         }
2115
2116                         break;
2117
2118                 default: /* backwards */
2119
2120                         if (pos < sample) {
2121                                 if ((distance = sample - pos) < closest) {
2122                                         closest = distance;
2123                                         ret = r;
2124                                 }
2125                         } else {
2126                                 end_iter = true;
2127                         }
2128
2129                         break;
2130                 }
2131         }
2132
2133         return ret;
2134 }
2135
2136  samplepos_t
2137  Playlist::find_next_region_boundary (samplepos_t sample, int dir)
2138  {
2139          RegionReadLock rlock (this);
2140
2141          samplepos_t closest = max_samplepos;
2142          samplepos_t ret = -1;
2143
2144          if (dir > 0) {
2145
2146                  for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2147
2148                          boost::shared_ptr<Region> r = (*i);
2149                          sampleoffset_t distance;
2150                          const samplepos_t first_sample = r->first_sample();
2151                          const samplepos_t last_sample = r->last_sample();
2152
2153                          if (first_sample > sample) {
2154
2155                                  distance = first_sample - sample;
2156
2157                                  if (distance < closest) {
2158                                          ret = first_sample;
2159                                          closest = distance;
2160                                  }
2161                          }
2162
2163                          if (last_sample > sample) {
2164
2165                                  distance = last_sample - sample;
2166
2167                                  if (distance < closest) {
2168                                          ret = last_sample;
2169                                          closest = distance;
2170                                  }
2171                          }
2172                  }
2173
2174          } else {
2175
2176                  for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2177
2178                          boost::shared_ptr<Region> r = (*i);
2179                          sampleoffset_t distance;
2180                          const samplepos_t first_sample = r->first_sample();
2181                          const samplepos_t last_sample = r->last_sample();
2182
2183                          if (last_sample < sample) {
2184
2185                                  distance = sample - last_sample;
2186
2187                                  if (distance < closest) {
2188                                          ret = last_sample;
2189                                          closest = distance;
2190                                  }
2191                          }
2192
2193                          if (first_sample < sample) {
2194
2195                                  distance = sample - first_sample;
2196
2197                                  if (distance < closest) {
2198                                          ret = first_sample;
2199                                          closest = distance;
2200                                  }
2201                          }
2202                  }
2203          }
2204
2205          return ret;
2206  }
2207
2208
2209  /***********************************************************************/
2210
2211
2212
2213
2214  void
2215  Playlist::mark_session_dirty ()
2216  {
2217          if (!in_set_state && !holding_state ()) {
2218                  _session.set_dirty();
2219          }
2220  }
2221
2222  void
2223  Playlist::rdiff (vector<Command*>& cmds) const
2224  {
2225          RegionReadLock rlock (const_cast<Playlist *> (this));
2226          Stateful::rdiff (cmds);
2227  }
2228
2229  void
2230  Playlist::clear_owned_changes ()
2231  {
2232          RegionReadLock rlock (this);
2233          Stateful::clear_owned_changes ();
2234  }
2235
2236  void
2237  Playlist::update (const RegionListProperty::ChangeRecord& change)
2238  {
2239          DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2240                                                          name(), change.added.size(), change.removed.size()));
2241
2242          freeze ();
2243          /* add the added regions */
2244          for (RegionListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
2245                  add_region_internal ((*i), (*i)->position());
2246          }
2247          /* remove the removed regions */
2248          for (RegionListProperty::ChangeContainer::const_iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2249                  remove_region (*i);
2250          }
2251
2252          thaw ();
2253  }
2254
2255  int
2256  Playlist::set_state (const XMLNode& node, int version)
2257  {
2258          XMLNode *child;
2259          XMLNodeList nlist;
2260          XMLNodeConstIterator niter;
2261          XMLPropertyConstIterator piter;
2262          boost::shared_ptr<Region> region;
2263          string region_name;
2264          bool seen_region_nodes = false;
2265          int ret = 0;
2266
2267          in_set_state++;
2268
2269          if (node.name() != "Playlist") {
2270                  in_set_state--;
2271                  return -1;
2272          }
2273
2274          freeze ();
2275
2276          set_id (node);
2277
2278          std::string name;
2279          if (node.get_property (X_("name"), name)) {
2280                  _name = name;
2281                  _set_sort_id ();
2282          }
2283
2284          /* XXX legacy session: fix up later */
2285          node.get_property (X_("orig-diskstream-id"), _orig_track_id);
2286
2287          node.get_property (X_("orig-track-id"), _orig_track_id);
2288          node.get_property (X_("frozen"), _frozen);
2289
2290          node.get_property (X_("combine-ops"), _combine_ops);
2291
2292          string shared_ids;
2293          if (node.get_property (X_("shared-with-ids"), shared_ids)) {
2294                  if (!shared_ids.empty()) {
2295                         vector<string> result;
2296                         ::split (shared_ids, result, ',');
2297                         vector<string>::iterator it = result.begin();
2298                         for (; it != result.end(); ++it) {
2299                                 _shared_with_ids.push_back (PBD::ID(*it));
2300                         }
2301                  }
2302          }
2303
2304          clear (true);
2305
2306          nlist = node.children();
2307
2308          for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2309
2310                  child = *niter;
2311
2312                  if (child->name() == "Region") {
2313
2314                          seen_region_nodes = true;
2315
2316                          ID id;
2317                          if (!child->get_property ("id", id)) {
2318                                  error << _("region state node has no ID, ignored") << endmsg;
2319                                  continue;
2320                          }
2321
2322                          if ((region = region_by_id (id))) {
2323
2324                                  region->suspend_property_changes ();
2325
2326                                  if (region->set_state (*child, version)) {
2327                                          region->resume_property_changes ();
2328                                          continue;
2329                                  }
2330
2331                          } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2332                                  region->suspend_property_changes ();
2333                          } else {
2334                                  error << _("Playlist: cannot create region from XML") << endmsg;
2335                                 return -1;
2336                         }
2337
2338                          {
2339                                  RegionWriteLock rlock (this);
2340                                  add_region_internal (region, region->position());
2341                          }
2342
2343                         region->resume_property_changes ();
2344
2345                 }
2346         }
2347
2348         if (seen_region_nodes && regions.empty()) {
2349                 ret = -1;
2350         }
2351
2352         thaw ();
2353         notify_contents_changed ();
2354
2355         in_set_state--;
2356         first_set_state = false;
2357
2358         return ret;
2359 }
2360
2361 XMLNode&
2362 Playlist::get_state()
2363 {
2364         return state (true);
2365 }
2366
2367 XMLNode&
2368 Playlist::get_template()
2369 {
2370         return state (false);
2371 }
2372
2373 /** @param full_state true to include regions in the returned state, otherwise false.
2374  */
2375 XMLNode&
2376 Playlist::state (bool full_state)
2377 {
2378         XMLNode *node = new XMLNode (X_("Playlist"));
2379
2380         node->set_property (X_("id"), id());
2381         node->set_property (X_("name"), name());
2382         node->set_property (X_("type"), _type);
2383         node->set_property (X_("orig-track-id"), _orig_track_id);
2384
2385         string shared_ids;
2386         list<PBD::ID>::const_iterator it = _shared_with_ids.begin();
2387         for (; it != _shared_with_ids.end(); ++it) {
2388                 shared_ids += "," + (*it).to_s();
2389         }
2390         if (!shared_ids.empty()) {
2391                 shared_ids.erase(0,1);
2392         }
2393
2394         node->set_property (X_("shared-with-ids"), shared_ids);
2395         node->set_property (X_("frozen"), _frozen);
2396
2397         if (full_state) {
2398                 RegionReadLock rlock (this);
2399
2400                 node->set_property ("combine-ops", _combine_ops);
2401
2402                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2403                         node->add_child_nocopy ((*i)->get_state());
2404                 }
2405         }
2406
2407         if (_extra_xml) {
2408                 node->add_child_copy (*_extra_xml);
2409         }
2410
2411         return *node;
2412 }
2413
2414 bool
2415 Playlist::empty() const
2416 {
2417         RegionReadLock rlock (const_cast<Playlist *>(this));
2418         return regions.empty();
2419 }
2420
2421 uint32_t
2422 Playlist::n_regions() const
2423 {
2424         RegionReadLock rlock (const_cast<Playlist *>(this));
2425         return regions.size();
2426 }
2427
2428 /** @return true if the all_regions list is empty, ie this playlist
2429  *  has never had a region added to it.
2430  */
2431 bool
2432 Playlist::all_regions_empty() const
2433 {
2434         RegionReadLock rl (const_cast<Playlist *> (this));
2435         return all_regions.empty();
2436 }
2437
2438 pair<samplepos_t, samplepos_t>
2439 Playlist::get_extent () const
2440 {
2441         RegionReadLock rlock (const_cast<Playlist *>(this));
2442         return _get_extent ();
2443 }
2444
2445 pair<samplepos_t, samplepos_t>
2446 Playlist::get_extent_with_endspace () const
2447 {
2448         pair<samplepos_t, samplepos_t> l = get_extent();
2449         l.second += _end_space;
2450         return l;
2451 }
2452
2453 pair<samplepos_t, samplepos_t>
2454 Playlist::_get_extent () const
2455 {
2456         pair<samplepos_t, samplepos_t> ext (max_samplepos, 0);
2457
2458         if (regions.empty()) {
2459                 ext.first = 0;
2460                 return ext;
2461         }
2462
2463         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2464                 pair<samplepos_t, samplepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2465                 if (e.first < ext.first) {
2466                         ext.first = e.first;
2467                 }
2468                 if (e.second > ext.second) {
2469                         ext.second = e.second;
2470                 }
2471         }
2472
2473         return ext;
2474 }
2475
2476 string
2477 Playlist::bump_name (string name, Session &session)
2478 {
2479         string newname = name;
2480
2481         do {
2482                 newname = bump_name_once (newname, '.');
2483         } while (session.playlists->by_name (newname)!=NULL);
2484
2485         return newname;
2486 }
2487
2488
2489 layer_t
2490 Playlist::top_layer() const
2491 {
2492         RegionReadLock rlock (const_cast<Playlist *> (this));
2493         layer_t top = 0;
2494
2495         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2496                 top = max (top, (*i)->layer());
2497         }
2498         return top;
2499 }
2500
2501 void
2502 Playlist::set_edit_mode (EditMode mode)
2503 {
2504         _edit_mode = mode;
2505 }
2506
2507 struct RelayerSort {
2508         bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2509                 return a->layering_index() < b->layering_index();
2510         }
2511 };
2512
2513 /** Set a new layer for a region.  This adjusts the layering indices of all
2514  *  regions in the playlist to put the specified region in the appropriate
2515  *  place.  The actual layering will be fixed up when relayer() happens.
2516  */
2517
2518 void
2519 Playlist::set_layer (boost::shared_ptr<Region> region, double new_layer)
2520 {
2521         /* Remove the layer we are setting from our region list, and sort it
2522         *  using the layer indeces.
2523         */
2524
2525         RegionList copy = regions.rlist();
2526         copy.remove (region);
2527         copy.sort (RelayerSort ());
2528
2529         /* Put region back in the right place */
2530         RegionList::iterator i = copy.begin();
2531         while (i != copy.end ()) {
2532                 if ((*i)->layer() > new_layer) {
2533                         break;
2534                 }
2535                 ++i;
2536         }
2537
2538         copy.insert (i, region);
2539
2540         setup_layering_indices (copy);
2541 }
2542
2543 void
2544 Playlist::setup_layering_indices (RegionList const & regions)
2545 {
2546         uint64_t j = 0;
2547
2548         for (RegionList::const_iterator k = regions.begin(); k != regions.end(); ++k) {
2549                 (*k)->set_layering_index (j++);
2550         }
2551 }
2552
2553 struct LaterHigherSort {
2554         bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2555                 return a->position() < b->position();
2556         }
2557 };
2558
2559 /** Take the layering indices of each of our regions, compute the layers
2560  *  that they should be on, and write the layers back to the regions.
2561  */
2562 void
2563 Playlist::relayer ()
2564 {
2565         /* never compute layers when setting from XML */
2566
2567         if (in_set_state) {
2568                 return;
2569         }
2570
2571         /* Build up a new list of regions on each layer, stored in a set of lists
2572            each of which represent some period of time on some layer.  The idea
2573            is to avoid having to search the entire region list to establish whether
2574            each region overlaps another */
2575
2576         /* how many pieces to divide this playlist's time up into */
2577         int const divisions = 512;
2578
2579         /* find the start and end positions of the regions on this playlist */
2580         samplepos_t start = INT64_MAX;
2581         samplepos_t end = 0;
2582         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2583                 start = min (start, (*i)->position());
2584                 end = max (end, (*i)->position() + (*i)->length());
2585         }
2586
2587         /* hence the size of each time division */
2588         double const division_size = (end - start) / double (divisions);
2589
2590         vector<vector<RegionList> > layers;
2591         layers.push_back (vector<RegionList> (divisions));
2592
2593         /* Sort our regions into layering index order (for manual layering) or position order (for later is higher)*/
2594         RegionList copy = regions.rlist();
2595         switch (Config->get_layer_model()) {
2596                 case LaterHigher:
2597                         copy.sort (LaterHigherSort ());
2598                         break;
2599                 case Manual:
2600                         copy.sort (RelayerSort ());
2601                         break;
2602         }
2603
2604         DEBUG_TRACE (DEBUG::Layering, "relayer() using:\n");
2605         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2606                 DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1 %2\n", (*i)->name(), (*i)->layering_index()));
2607         }
2608
2609         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2610
2611                 /* find the time divisions that this region covers; if there are no regions on the list,
2612                    division_size will equal 0 and in this case we'll just say that
2613                    start_division = end_division = 0.
2614                 */
2615                 int start_division = 0;
2616                 int end_division = 0;
2617
2618                 if (division_size > 0) {
2619                         start_division = floor ( ((*i)->position() - start) / division_size);
2620                         end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2621                         if (end_division == divisions) {
2622                                 end_division--;
2623                         }
2624                 }
2625
2626                 assert (divisions == 0 || end_division < divisions);
2627
2628                 /* find the lowest layer that this region can go on */
2629                 size_t j = layers.size();
2630                 while (j > 0) {
2631                         /* try layer j - 1; it can go on if it overlaps no other region
2632                            that is already on that layer
2633                         */
2634
2635                         bool overlap = false;
2636                         for (int k = start_division; k <= end_division; ++k) {
2637                                 RegionList::iterator l = layers[j-1][k].begin ();
2638                                 while (l != layers[j-1][k].end()) {
2639                                         if ((*l)->overlap_equivalent (*i)) {
2640                                                 overlap = true;
2641                                                 break;
2642                                         }
2643                                         l++;
2644                                 }
2645
2646                                 if (overlap) {
2647                                         break;
2648                                 }
2649                         }
2650
2651                         if (overlap) {
2652                                 /* overlap, so we must use layer j */
2653                                 break;
2654                         }
2655
2656                         --j;
2657                 }
2658
2659                 if (j == layers.size()) {
2660                         /* we need a new layer for this region */
2661                         layers.push_back (vector<RegionList> (divisions));
2662                 }
2663
2664                 /* put a reference to this region in each of the divisions that it exists in */
2665                 for (int k = start_division; k <= end_division; ++k) {
2666                         layers[j][k].push_back (*i);
2667                 }
2668
2669                 (*i)->set_layer (j);
2670         }
2671
2672         /* It's a little tricky to know when we could avoid calling this; e.g. if we are
2673            relayering because we just removed the only region on the top layer, nothing will
2674            appear to have changed, but the StreamView must still sort itself out.  We could
2675            probably keep a note of the top layer last time we relayered, and check that,
2676            but premature optimisation &c...
2677         */
2678         notify_layering_changed ();
2679
2680         /* This relayer() may have been called as a result of a region removal, in which
2681            case we need to setup layering indices to account for the one that has just
2682            gone away.
2683         */
2684         setup_layering_indices (copy);
2685 }
2686
2687 void
2688 Playlist::raise_region (boost::shared_ptr<Region> region)
2689 {
2690         set_layer (region, region->layer() + 1.5);
2691         relayer ();
2692 }
2693
2694 void
2695 Playlist::lower_region (boost::shared_ptr<Region> region)
2696 {
2697         set_layer (region, region->layer() - 1.5);
2698         relayer ();
2699 }
2700
2701 void
2702 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2703 {
2704         set_layer (region, DBL_MAX);
2705         relayer ();
2706 }
2707
2708 void
2709 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2710 {
2711         set_layer (region, -0.5);
2712         relayer ();
2713 }
2714
2715 void
2716 Playlist::nudge_after (samplepos_t start, samplecnt_t distance, bool forwards)
2717 {
2718         RegionList::iterator i;
2719         bool moved = false;
2720
2721         _nudging = true;
2722
2723         {
2724                 RegionWriteLock rlock (const_cast<Playlist *> (this));
2725
2726                 for (i = regions.begin(); i != regions.end(); ++i) {
2727
2728                         if ((*i)->position() >= start) {
2729
2730                                 samplepos_t new_pos;
2731
2732                                 if (forwards) {
2733
2734                                         if ((*i)->last_sample() > max_samplepos - distance) {
2735                                                 new_pos = max_samplepos - (*i)->length();
2736                                         } else {
2737                                                 new_pos = (*i)->position() + distance;
2738                                         }
2739
2740                                 } else {
2741
2742                                         if ((*i)->position() > distance) {
2743                                                 new_pos = (*i)->position() - distance;
2744                                         } else {
2745                                                 new_pos = 0;
2746                                         }
2747                                 }
2748
2749                                 (*i)->set_position (new_pos);
2750                                 moved = true;
2751                         }
2752                 }
2753         }
2754
2755         if (moved) {
2756                 _nudging = false;
2757                 notify_contents_changed ();
2758         }
2759
2760 }
2761
2762 bool
2763 Playlist::uses_source (boost::shared_ptr<const Source> src, bool shallow) const
2764 {
2765         RegionReadLock rlock (const_cast<Playlist*> (this));
2766
2767         for (set<boost::shared_ptr<Region> >::const_iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
2768                 /* Note: passing the second argument as false can cause at best
2769                    incredibly deep and time-consuming recursion, and at worst
2770                    cycles if the user has managed to create cycles of reference
2771                    between compound regions. We generally only this during
2772                    cleanup, and @param shallow is passed as true.
2773                 */
2774                 if ((*r)->uses_source (src, shallow)) {
2775                         return true;
2776                 }
2777         }
2778
2779         return false;
2780 }
2781
2782
2783 boost::shared_ptr<Region>
2784 Playlist::find_region (const ID& id) const
2785 {
2786         RegionReadLock rlock (const_cast<Playlist*> (this));
2787
2788         /* searches all regions currently in use by the playlist */
2789
2790         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2791                 if ((*i)->id() == id) {
2792                         return *i;
2793                 }
2794         }
2795
2796         return boost::shared_ptr<Region> ();
2797 }
2798
2799 uint32_t
2800 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2801 {
2802         RegionReadLock rlock (const_cast<Playlist*> (this));
2803         uint32_t cnt = 0;
2804
2805         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2806                 if ((*i) == r) {
2807                         cnt++;
2808                 }
2809         }
2810
2811         RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
2812         for (RegionFactory::CompoundAssociations::iterator it = cassocs.begin(); it != cassocs.end(); ++it) {
2813                 /* check if region is used in a compound */
2814                 if (it->second == r) {
2815                         /* region is referenced as 'original' of a compound */
2816                         ++cnt;
2817                         break;
2818                 }
2819                 if (r->whole_file() && r->max_source_level() > 0) {
2820                         /* region itself ia a compound.
2821                          * the compound regions are not referenced -> check regions inside compound
2822                          */
2823                         const SourceList& sl = r->sources();
2824                         for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
2825                                 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource>(*s);
2826                                 if (!ps) continue;
2827                                 if (ps->playlist()->region_use_count(it->first)) {
2828                                         // break out of both loops
2829                                         return ++cnt;
2830                                 }
2831                         }
2832                 }
2833         }
2834         return cnt;
2835 }
2836
2837 boost::shared_ptr<Region>
2838 Playlist::region_by_id (const ID& id) const
2839 {
2840         /* searches all regions ever added to this playlist */
2841
2842         for (set<boost::shared_ptr<Region> >::const_iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2843                 if ((*i)->id() == id) {
2844                         return *i;
2845                 }
2846         }
2847         return boost::shared_ptr<Region> ();
2848 }
2849
2850 void
2851 Playlist::dump () const
2852 {
2853         boost::shared_ptr<Region> r;
2854
2855         cerr << "Playlist \"" << _name << "\" " << endl
2856              << regions.size() << " regions "
2857              << endl;
2858
2859         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2860                 r = *i;
2861                 cerr << "  " << r->name() << " ["
2862                      << r->start() << "+" << r->length()
2863                      << "] at "
2864                      << r->position()
2865                      << " on layer "
2866                      << r->layer ()
2867                      << endl;
2868         }
2869 }
2870
2871 void
2872 Playlist::set_frozen (bool yn)
2873 {
2874         _frozen = yn;
2875 }
2876
2877 void
2878 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2879 {
2880         bool moved = false;
2881
2882         if (region->locked()) {
2883                 return;
2884         }
2885
2886         _shuffling = true;
2887
2888         {
2889                 RegionWriteLock rlock (const_cast<Playlist*> (this));
2890
2891
2892                 if (dir > 0) {
2893
2894                         RegionList::iterator next;
2895
2896                         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2897                                 if ((*i) == region) {
2898                                         next = i;
2899                                         ++next;
2900
2901                                         if (next != regions.end()) {
2902
2903                                                 if ((*next)->locked()) {
2904                                                         break;
2905                                                 }
2906
2907                                                 samplepos_t new_pos;
2908
2909                                                 if ((*next)->position() != region->last_sample() + 1) {
2910                                                         /* they didn't used to touch, so after shuffle,
2911                                                            just have them swap positions.
2912                                                         */
2913                                                         new_pos = (*next)->position();
2914                                                 } else {
2915                                                         /* they used to touch, so after shuffle,
2916                                                            make sure they still do. put the earlier
2917                                                            region where the later one will end after
2918                                                            it is moved.
2919                                                         */
2920                                                         new_pos = region->position() + (*next)->length();
2921                                                 }
2922
2923                                                 (*next)->set_position (region->position());
2924                                                 region->set_position (new_pos);
2925
2926                                                 /* avoid a full sort */
2927
2928                                                 regions.erase (i); // removes the region from the list */
2929                                                 next++;
2930                                                 regions.insert (next, region); // adds it back after next
2931
2932                                                 moved = true;
2933                                         }
2934                                         break;
2935                                 }
2936                         }
2937                 } else {
2938
2939                         RegionList::iterator prev = regions.end();
2940
2941                         for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2942                                 if ((*i) == region) {
2943
2944                                         if (prev != regions.end()) {
2945
2946                                                 if ((*prev)->locked()) {
2947                                                         break;
2948                                                 }
2949
2950                                                 samplepos_t new_pos;
2951                                                 if (region->position() != (*prev)->last_sample() + 1) {
2952                                                         /* they didn't used to touch, so after shuffle,
2953                                                            just have them swap positions.
2954                                                         */
2955                                                         new_pos = region->position();
2956                                                 } else {
2957                                                         /* they used to touch, so after shuffle,
2958                                                            make sure they still do. put the earlier
2959                                                            one where the later one will end after
2960                                                         */
2961                                                         new_pos = (*prev)->position() + region->length();
2962                                                 }
2963
2964                                                 region->set_position ((*prev)->position());
2965                                                 (*prev)->set_position (new_pos);
2966
2967                                                 /* avoid a full sort */
2968
2969                                                 regions.erase (i); // remove region
2970                                                 regions.insert (prev, region); // insert region before prev
2971
2972                                                 moved = true;
2973                                         }
2974
2975                                         break;
2976                                 }
2977                         }
2978                 }
2979         }
2980
2981         _shuffling = false;
2982
2983         if (moved) {
2984
2985                 relayer ();
2986                 notify_contents_changed();
2987         }
2988
2989 }
2990
2991 bool
2992 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2993 {
2994         RegionReadLock rlock (const_cast<Playlist*> (this));
2995
2996         if (regions.size() > 1) {
2997                 return true;
2998         }
2999
3000         return false;
3001 }
3002
3003 void
3004 Playlist::ripple (samplepos_t at, samplecnt_t distance, RegionList *exclude)
3005 {
3006         ripple_locked (at, distance, exclude);
3007 }
3008
3009 void
3010 Playlist::update_after_tempo_map_change ()
3011 {
3012         RegionWriteLock rlock (const_cast<Playlist*> (this));
3013         RegionList copy (regions.rlist());
3014
3015         freeze ();
3016
3017         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
3018                 (*i)->update_after_tempo_map_change ();
3019         }
3020         /* possibly causes a contents changed notification (flush_notifications()) */
3021         thaw ();
3022 }
3023
3024 void
3025 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
3026 {
3027         RegionReadLock rl (this);
3028         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
3029                 s (*i);
3030         }
3031 }
3032
3033 bool
3034 Playlist::has_region_at (samplepos_t const p) const
3035 {
3036         RegionReadLock (const_cast<Playlist *> (this));
3037
3038         RegionList::const_iterator i = regions.begin ();
3039         while (i != regions.end() && !(*i)->covers (p)) {
3040                 ++i;
3041         }
3042
3043         return (i != regions.end());
3044 }
3045
3046 /** Look from a session sample time and find the start time of the next region
3047  *  which is on the top layer of this playlist.
3048  *  @param t Time to look from.
3049  *  @return Position of next top-layered region, or max_samplepos if there isn't one.
3050  */
3051 samplepos_t
3052 Playlist::find_next_top_layer_position (samplepos_t t) const
3053 {
3054         RegionReadLock rlock (const_cast<Playlist *> (this));
3055
3056         layer_t const top = top_layer ();
3057
3058         RegionList copy = regions.rlist ();
3059         copy.sort (RegionSortByPosition ());
3060
3061         for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3062                 if ((*i)->position() >= t && (*i)->layer() == top) {
3063                         return (*i)->position();
3064                 }
3065         }
3066
3067         return max_samplepos;
3068 }
3069
3070 boost::shared_ptr<Region>
3071 Playlist::combine (const RegionList& r)
3072 {
3073         PropertyList plist;
3074         uint32_t channels = 0;
3075         uint32_t layer = 0;
3076         samplepos_t earliest_position = max_samplepos;
3077         vector<TwoRegions> old_and_new_regions;
3078         vector<boost::shared_ptr<Region> > originals;
3079         vector<boost::shared_ptr<Region> > copies;
3080         string parent_name;
3081         string child_name;
3082         uint32_t max_level = 0;
3083
3084         /* find the maximum depth of all the regions we're combining */
3085
3086         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3087                 max_level = max (max_level, (*i)->max_source_level());
3088         }
3089
3090         parent_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, true);
3091         child_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, false);
3092
3093         boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, parent_name, true);
3094
3095         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3096                 earliest_position = min (earliest_position, (*i)->position());
3097         }
3098
3099         /* enable this so that we do not try to create xfades etc. as we add
3100          * regions
3101          */
3102
3103         pl->in_partition = true;
3104
3105         /* sort by position then layer.
3106          * route_time_axis passes 'selected_regions' - which is not sorted.
3107          * here we need the top-most first, then every layer's region sorted by position.
3108          */
3109         RegionList sorted(r);
3110         sorted.sort(RegionSortByLayerAndPosition());
3111
3112         for (RegionList::const_iterator i = sorted.begin(); i != sorted.end(); ++i) {
3113
3114                 /* copy the region */
3115
3116                 boost::shared_ptr<Region> original_region = (*i);
3117                 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
3118
3119                 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
3120                 originals.push_back (original_region);
3121                 copies.push_back (copied_region);
3122
3123                 RegionFactory::add_compound_association (original_region, copied_region);
3124
3125                 /* make position relative to zero */
3126
3127                 pl->add_region (copied_region, original_region->position() - earliest_position);
3128                 copied_region->set_layer (original_region->layer ());
3129
3130                 /* use the maximum number of channels for any region */
3131
3132                 channels = max (channels, original_region->n_channels());
3133
3134                 /* it will go above the layer of the highest existing region */
3135
3136                 layer = max (layer, original_region->layer());
3137         }
3138
3139         pl->in_partition = false;
3140
3141         pre_combine (copies);
3142
3143         /* now create a new PlaylistSource for each channel in the new playlist */
3144
3145         SourceList sources;
3146         pair<samplepos_t,samplepos_t> extent = pl->get_extent();
3147
3148         for (uint32_t chn = 0; chn < channels; ++chn) {
3149                 sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, id(), parent_name, chn, 0, extent.second, false, false));
3150
3151         }
3152
3153         /* now a new whole-file region using the list of sources */
3154
3155         plist.add (Properties::start, 0);
3156         plist.add (Properties::length, extent.second);
3157         plist.add (Properties::name, parent_name);
3158         plist.add (Properties::whole_file, true);
3159
3160         boost::shared_ptr<Region> parent_region = RegionFactory::create (sources, plist, true);
3161
3162         /* now the non-whole-file region that we will actually use in the
3163          * playlist
3164          */
3165
3166         plist.clear ();
3167         plist.add (Properties::start, 0);
3168         plist.add (Properties::length, extent.second);
3169         plist.add (Properties::name, child_name);
3170         plist.add (Properties::layer, layer+1);
3171
3172         boost::shared_ptr<Region> compound_region = RegionFactory::create (parent_region, plist, true);
3173
3174         /* remove all the selected regions from the current playlist
3175          */
3176
3177         freeze ();
3178
3179         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
3180                 remove_region (*i);
3181         }
3182
3183         /* do type-specific stuff with the originals and the new compound
3184            region
3185         */
3186
3187         post_combine (originals, compound_region);
3188
3189         /* add the new region at the right location */
3190
3191         add_region (compound_region, earliest_position);
3192
3193         _combine_ops++;
3194
3195         thaw ();
3196
3197         return compound_region;
3198 }
3199
3200 void
3201 Playlist::uncombine (boost::shared_ptr<Region> target)
3202 {
3203         boost::shared_ptr<PlaylistSource> pls;
3204         boost::shared_ptr<const Playlist> pl;
3205         vector<boost::shared_ptr<Region> > originals;
3206         vector<TwoRegions> old_and_new_regions;
3207
3208         // (1) check that its really a compound region
3209
3210         if ((pls = boost::dynamic_pointer_cast<PlaylistSource>(target->source (0))) == 0) {
3211                 return;
3212         }
3213
3214         pl = pls->playlist();
3215
3216         samplepos_t adjusted_start = 0; // gcc isn't smart enough
3217         samplepos_t adjusted_end = 0;   // gcc isn't smart enough
3218
3219         /* the leftmost (earliest) edge of the compound region
3220            starts at zero in its source, or larger if it
3221            has been trimmed or content-scrolled.
3222
3223            the rightmost (latest) edge of the compound region
3224            relative to its source is the starting point plus
3225            the length of the region.
3226         */
3227
3228         // (2) get all the original regions
3229
3230         const RegionList& rl (pl->region_list_property().rlist());
3231         RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
3232         sampleoffset_t move_offset = 0;
3233
3234         /* there are two possibilities here:
3235            1) the playlist that the playlist source was based on
3236            is us, so just add the originals (which belonged to
3237            us anyway) back in the right place.
3238
3239            2) the playlist that the playlist source was based on
3240            is NOT us, so we need to make copies of each of
3241            the original regions that we find, and add them
3242            instead.
3243         */
3244         bool same_playlist = (pls->original() == id());
3245
3246         for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
3247
3248                 boost::shared_ptr<Region> current (*i);
3249
3250                 RegionFactory::CompoundAssociations::iterator ca = cassocs.find (*i);
3251
3252                 if (ca == cassocs.end()) {
3253                         continue;
3254                 }
3255
3256                 boost::shared_ptr<Region> original (ca->second);
3257                 cassocs.erase(ca);
3258                 bool modified_region;
3259
3260                 if (i == rl.begin()) {
3261                         move_offset = (target->position() - original->position()) - target->start();
3262                         adjusted_start = original->position() + target->start();
3263                         adjusted_end = adjusted_start + target->length();
3264                 }
3265
3266                 if (!same_playlist) {
3267                         samplepos_t pos = original->position();
3268                         /* make a copy, but don't announce it */
3269                         original = RegionFactory::create (original, false);
3270                         /* the pure copy constructor resets position() to zero,
3271                            so fix that up.
3272                         */
3273                         original->set_position (pos);
3274                 }
3275
3276                 /* check to see how the original region (in the
3277                  * playlist before compounding occurred) overlaps
3278                  * with the new state of the compound region.
3279                  */
3280
3281                 original->clear_changes ();
3282                 modified_region = false;
3283
3284                 switch (original->coverage (adjusted_start, adjusted_end)) {
3285                 case Evoral::OverlapNone:
3286                         /* original region does not cover any part
3287                            of the current state of the compound region
3288                         */
3289                         continue;
3290
3291                 case Evoral::OverlapInternal:
3292                         /* overlap is just a small piece inside the
3293                          * original so trim both ends
3294                          */
3295                         original->trim_to (adjusted_start, adjusted_end - adjusted_start);
3296                         modified_region = true;
3297                         break;
3298
3299                 case Evoral::OverlapExternal:
3300                         /* overlap fully covers original, so leave it
3301                            as is
3302                         */
3303                         break;
3304
3305                 case Evoral::OverlapEnd:
3306                         /* overlap starts within but covers end,
3307                            so trim the front of the region
3308                         */
3309                         original->trim_front (adjusted_start);
3310                         modified_region = true;
3311                         break;
3312
3313                 case Evoral::OverlapStart:
3314                         /* overlap covers start but ends within, so
3315                          * trim the end of the region.
3316                          */
3317                         original->trim_end (adjusted_end);
3318                         modified_region = true;
3319                         break;
3320                 }
3321
3322                 if (move_offset) {
3323                         /* fix the position to match any movement of the compound region.
3324                          */
3325                         original->set_position (original->position() + move_offset);
3326                         modified_region = true;
3327                 }
3328
3329                 if (modified_region) {
3330                         _session.add_command (new StatefulDiffCommand (original));
3331                 }
3332
3333                 /* and add to the list of regions waiting to be
3334                  * re-inserted
3335                  */
3336
3337                 originals.push_back (original);
3338                 old_and_new_regions.push_back (TwoRegions (*i, original));
3339         }
3340
3341         pre_uncombine (originals, target);
3342
3343         in_partition = true;
3344         freeze ();
3345
3346         // (3) remove the compound region
3347
3348         remove_region (target);
3349
3350         // (4) add the constituent regions
3351
3352         for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
3353                 add_region ((*i), (*i)->position());
3354                 set_layer((*i), (*i)->layer());
3355                 if (!RegionFactory::region_by_id((*i)->id())) {
3356                         RegionFactory::map_add(*i);
3357                 }
3358         }
3359
3360         in_partition = false;
3361         thaw ();
3362 }
3363
3364 void
3365 Playlist::fade_range (list<AudioRange>& ranges)
3366 {
3367         RegionReadLock rlock (this);
3368         for (list<AudioRange>::iterator r = ranges.begin(); r != ranges.end(); ) {
3369                 list<AudioRange>::iterator tmpr = r;
3370                 ++tmpr;
3371                 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ) {
3372                         RegionList::const_iterator tmpi = i;
3373                         ++tmpi;
3374                         (*i)->fade_range ((*r).start, (*r).end);
3375                         i = tmpi;
3376                 }
3377                 r = tmpr;
3378         }
3379 }
3380
3381 uint32_t
3382 Playlist::max_source_level () const
3383 {
3384         RegionReadLock rlock (const_cast<Playlist *> (this));
3385         uint32_t lvl = 0;
3386
3387         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3388                 lvl = max (lvl, (*i)->max_source_level());
3389         }
3390
3391         return lvl;
3392 }
3393
3394 void
3395 Playlist::set_orig_track_id (const PBD::ID& id)
3396 {
3397         if (shared_with(id)) {
3398                 // Swap 'shared_id' / origin_track_id
3399                 unshare_with (id);
3400                 share_with (_orig_track_id);
3401         }
3402         _orig_track_id = id;
3403 }
3404
3405 void
3406 Playlist::share_with (const PBD::ID& id)
3407 {
3408         if (!shared_with(id)) {
3409                 _shared_with_ids.push_back (id);
3410         }
3411 }
3412
3413 void
3414 Playlist::unshare_with (const PBD::ID& id)
3415 {
3416         list<PBD::ID>::iterator it = _shared_with_ids.begin ();
3417         while (it != _shared_with_ids.end()) {
3418                 if (*it == id) {
3419                         _shared_with_ids.erase (it);
3420                         break;
3421                 }
3422                 ++it;
3423         }
3424 }
3425
3426 bool
3427 Playlist::shared_with (const PBD::ID& id) const
3428 {
3429         bool shared = false;
3430         list<PBD::ID>::const_iterator it = _shared_with_ids.begin ();
3431         while (it != _shared_with_ids.end() && !shared) {
3432                 if (*it == id) {
3433                         shared = true;
3434                 }
3435                 ++it;
3436         }
3437
3438         return shared;
3439 }
3440
3441 void
3442 Playlist::reset_shares ()
3443 {
3444         _shared_with_ids.clear();
3445 }
3446
3447 /** Take a list of ranges, coalesce any that can be coalesced, then call
3448  *  check_crossfades for each one.
3449  */
3450 void
3451 Playlist::coalesce_and_check_crossfades (list<Evoral::Range<samplepos_t> > ranges)
3452 {
3453         /* XXX: it's a shame that this coalesce algorithm also exists in
3454            TimeSelection::consolidate().
3455         */
3456
3457         /* XXX: xfade: this is implemented in Evoral::RangeList */
3458
3459 restart:
3460         for (list<Evoral::Range<samplepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
3461                 for (list<Evoral::Range<samplepos_t> >::iterator j = ranges.begin(); j != ranges.end(); ++j) {
3462
3463                         if (i == j) {
3464                                 continue;
3465                         }
3466
3467                         // XXX i->from can be > i->to - is this right? coverage() will return OverlapNone in this case
3468                         if (Evoral::coverage (i->from, i->to, j->from, j->to) != Evoral::OverlapNone) {
3469                                 i->from = min (i->from, j->from);
3470                                 i->to = max (i->to, j->to);
3471                                 ranges.erase (j);
3472                                 goto restart;
3473                         }
3474                 }
3475         }
3476 }
3477
3478 void
3479 Playlist::set_capture_insertion_in_progress (bool yn)
3480 {
3481         _capture_insertion_underway = yn;
3482 }