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