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