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