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