stop deadlock when pasting into a playlist
[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         RegionReadLock 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         RegionReadLock 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                 RegionReadLock 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          RegionWriteLock 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          RegionWriteLock 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          RegionWriteLock 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          RegionWriteLock 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                  RegionWriteLock 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                  RegionReadLock rl2 (other.get());
1200
1201                  int itimes = (int) floor (times);
1202                  framepos_t pos = position;
1203                  framecnt_t const shift = other->_get_extent().second;
1204                  layer_t top = top_layer ();
1205
1206                  {
1207                          RegionWriteLock rl1 (this);
1208                          while (itimes--) {
1209                                  for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1210                                          boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1211                                          
1212                                          /* put these new regions on top of all existing ones, but preserve
1213                                             the ordering they had in the original playlist.
1214                                          */
1215                                          
1216                                          add_region_internal (copy_of_region, (*i)->position() + pos);
1217                                          set_layer (copy_of_region, copy_of_region->layer() + top);
1218                                  }
1219                                  pos += shift;
1220                          }
1221                  }
1222          }
1223
1224          return 0;
1225  }
1226
1227
1228  void
1229  Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1230  {
1231          times = fabs (times);
1232
1233          RegionWriteLock rl (this);
1234          int itimes = (int) floor (times);
1235          framepos_t pos = position + 1;
1236
1237          while (itimes--) {
1238                  boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1239                  add_region_internal (copy, pos);
1240                  set_layer (copy, DBL_MAX);
1241                  pos += region->length();
1242          }
1243
1244          if (floor (times) != times) {
1245                  framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1246                  string name;
1247                  RegionFactory::region_name (name, region->name(), false);
1248
1249                  {
1250                          PropertyList plist;
1251
1252                          plist.add (Properties::start, region->start());
1253                          plist.add (Properties::length, length);
1254                          plist.add (Properties::name, name);
1255
1256                          boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1257                          add_region_internal (sub, pos);
1258                          set_layer (sub, DBL_MAX);
1259                  }
1260          }
1261  }
1262
1263  void
1264  Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1265  {
1266          RegionWriteLock rlock (this);
1267          RegionList copy (regions.rlist());
1268          RegionList fixup;
1269
1270          for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1271
1272                  if ((*r)->last_frame() < at) {
1273                          /* too early */
1274                          continue;
1275                  }
1276
1277                  if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1278                          /* intersected region */
1279                          if (!move_intersected) {
1280                                  continue;
1281                          }
1282                  }
1283
1284                  /* do not move regions glued to music time - that
1285                     has to be done separately.
1286                  */
1287
1288                  if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1289                          fixup.push_back (*r);
1290                          continue;
1291                  }
1292
1293                  (*r)->set_position ((*r)->position() + distance);
1294          }
1295
1296          /* XXX: may not be necessary; Region::post_set should do this, I think */
1297          for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1298                  (*r)->recompute_position_from_lock_style ();
1299          }
1300  }
1301
1302  void
1303  Playlist::split (framepos_t at)
1304  {
1305          RegionWriteLock rlock (this);
1306          RegionList copy (regions.rlist());
1307
1308          /* use a copy since this operation can modify the region list
1309           */
1310
1311          for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1312                  _split_region (*r, at);
1313          }
1314  }
1315
1316  void
1317  Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1318  {
1319          RegionWriteLock rl (this);
1320          _split_region (region, playlist_position);
1321  }
1322
1323  void
1324  Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1325  {
1326          if (!region->covers (playlist_position)) {
1327                  return;
1328          }
1329
1330          if (region->position() == playlist_position ||
1331              region->last_frame() == playlist_position) {
1332                  return;
1333          }
1334
1335          boost::shared_ptr<Region> left;
1336          boost::shared_ptr<Region> right;
1337          frameoffset_t before;
1338          frameoffset_t after;
1339          string before_name;
1340          string after_name;
1341
1342          /* split doesn't change anything about length, so don't try to splice */
1343
1344          bool old_sp = _splicing;
1345          _splicing = true;
1346
1347          before = playlist_position - region->position();
1348          after = region->length() - before;
1349
1350          RegionFactory::region_name (before_name, region->name(), false);
1351
1352          {
1353                  PropertyList plist;
1354
1355                  plist.add (Properties::position, region->position ());
1356                  plist.add (Properties::length, before);
1357                  plist.add (Properties::name, before_name);
1358                  plist.add (Properties::left_of_split, true);
1359                  plist.add (Properties::layering_index, region->layering_index ());
1360                  plist.add (Properties::layer, region->layer ());
1361
1362                  /* note: we must use the version of ::create with an offset here,
1363                     since it supplies that offset to the Region constructor, which
1364                     is necessary to get audio region gain envelopes right.
1365                  */
1366                  left = RegionFactory::create (region, 0, plist);
1367          }
1368
1369          RegionFactory::region_name (after_name, region->name(), false);
1370
1371          {
1372                  PropertyList plist;
1373
1374                  plist.add (Properties::position, region->position() + before);
1375                  plist.add (Properties::length, after);
1376                  plist.add (Properties::name, after_name);
1377                  plist.add (Properties::right_of_split, true);
1378                  plist.add (Properties::layering_index, region->layering_index ());
1379                  plist.add (Properties::layer, region->layer ());
1380
1381                  /* same note as above */
1382                  right = RegionFactory::create (region, before, plist);
1383          }
1384
1385          add_region_internal (left, region->position());
1386          add_region_internal (right, region->position() + before);
1387          remove_region_internal (region);
1388
1389          _splicing = old_sp;
1390  }
1391
1392  void
1393  Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1394  {
1395          if (_splicing || in_set_state) {
1396                  /* don't respond to splicing moves or state setting */
1397                  return;
1398          }
1399
1400          if (_edit_mode == Splice) {
1401                  splice_locked (at, distance, exclude);
1402          }
1403  }
1404
1405  void
1406  Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1407  {
1408          if (_splicing || in_set_state) {
1409                  /* don't respond to splicing moves or state setting */
1410                  return;
1411          }
1412
1413          if (_edit_mode == Splice) {
1414                  splice_unlocked (at, distance, exclude);
1415          }
1416  }
1417
1418  void
1419  Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1420  {
1421          {
1422                  RegionWriteLock rl (this);
1423                  core_splice (at, distance, exclude);
1424          }
1425  }
1426
1427  void
1428  Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1429  {
1430          core_splice (at, distance, exclude);
1431  }
1432
1433  void
1434  Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1435  {
1436          _splicing = true;
1437
1438          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1439
1440                  if (exclude && (*i) == exclude) {
1441                          continue;
1442                  }
1443
1444                  if ((*i)->position() >= at) {
1445                          framepos_t new_pos = (*i)->position() + distance;
1446                          if (new_pos < 0) {
1447                                  new_pos = 0;
1448                          } else if (new_pos >= max_framepos - (*i)->length()) {
1449                                  new_pos = max_framepos - (*i)->length();
1450                          }
1451
1452                          (*i)->set_position (new_pos);
1453                  }
1454          }
1455
1456          _splicing = false;
1457
1458          notify_contents_changed ();
1459  }
1460
1461  void
1462  Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1463  {
1464          if (in_set_state || _splicing || _nudging || _shuffling) {
1465                  return;
1466          }
1467
1468          if (what_changed.contains (Properties::position)) {
1469
1470                  /* remove it from the list then add it back in
1471                     the right place again.
1472                  */
1473
1474                  RegionSortByPosition cmp;
1475
1476                  RegionList::iterator i = find (regions.begin(), regions.end(), region);
1477
1478                  if (i == regions.end()) {
1479                          /* the region bounds are being modified but its not currently
1480                             in the region list. we will use its bounds correctly when/if
1481                             it is added
1482                          */
1483                          return;
1484                  }
1485
1486                  regions.erase (i);
1487                  regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1488          }
1489
1490          if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1491
1492                  frameoffset_t delta = 0;
1493
1494                  if (what_changed.contains (Properties::position)) {
1495                          delta = region->position() - region->last_position();
1496                  }
1497
1498                  if (what_changed.contains (Properties::length)) {
1499                          delta += region->length() - region->last_length();
1500                  }
1501
1502                  if (delta) {
1503                          possibly_splice (region->last_position() + region->last_length(), delta, region);
1504                  }
1505
1506                  if (holding_state ()) {
1507                          pending_bounds.push_back (region);
1508                  } else {
1509                          notify_contents_changed ();
1510                          relayer ();
1511                          list<Evoral::Range<framepos_t> > xf;
1512                          xf.push_back (Evoral::Range<framepos_t> (region->last_range()));
1513                          xf.push_back (Evoral::Range<framepos_t> (region->range()));
1514                          coalesce_and_check_crossfades (xf);
1515                  }
1516          }
1517  }
1518
1519  void
1520  Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1521  {
1522          boost::shared_ptr<Region> region (weak_region.lock());
1523
1524          if (!region) {
1525                  return;
1526          }
1527
1528          /* this makes a virtual call to the right kind of playlist ... */
1529
1530          region_changed (what_changed, region);
1531  }
1532
1533  bool
1534  Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1535  {
1536          PropertyChange our_interests;
1537          PropertyChange bounds;
1538          PropertyChange pos_and_length;
1539          bool save = false;
1540
1541          if (in_set_state || in_flush) {
1542                  return false;
1543          }
1544
1545          our_interests.add (Properties::muted);
1546          our_interests.add (Properties::layer);
1547          our_interests.add (Properties::opaque);
1548
1549          bounds.add (Properties::start);
1550          bounds.add (Properties::position);
1551          bounds.add (Properties::length);
1552
1553          pos_and_length.add (Properties::position);
1554          pos_and_length.add (Properties::length);
1555
1556          if (what_changed.contains (bounds)) {
1557                  region_bounds_changed (what_changed, region);
1558                  save = !(_splicing || _nudging);
1559          }
1560
1561          if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1562                  check_crossfades (region->range ());
1563          }
1564
1565          if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1566                  notify_region_moved (region);
1567          } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1568                  notify_region_end_trimmed (region);
1569          } else if (what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) {
1570                  notify_region_start_trimmed (region);
1571          }
1572
1573          /* don't notify about layer changes, since we are the only object that can initiate
1574             them, and we notify in ::relayer()
1575          */
1576
1577          if (what_changed.contains (our_interests)) {
1578                  save = true;
1579          }
1580
1581          return save;
1582  }
1583
1584  void
1585  Playlist::drop_regions ()
1586  {
1587          RegionWriteLock rl (this);
1588          regions.clear ();
1589          all_regions.clear ();
1590  }
1591
1592  void
1593  Playlist::sync_all_regions_with_regions ()
1594  {
1595          RegionWriteLock rl (this);
1596
1597          all_regions.clear ();
1598
1599          for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1600                  all_regions.insert (*i);
1601          }
1602  }
1603
1604  void
1605  Playlist::clear (bool with_signals)
1606  {
1607          {
1608                  RegionWriteLock rl (this);
1609
1610                  region_state_changed_connections.drop_connections ();
1611
1612                  for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1613                          pending_removes.insert (*i);
1614                  }
1615
1616                  regions.clear ();
1617
1618                  for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1619                          remove_dependents (*s);
1620                  }
1621          }
1622
1623          if (with_signals) {
1624
1625                  for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1626                          RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1627                  }
1628
1629                  pending_removes.clear ();
1630                  pending_contents_change = false;
1631                  ContentsChanged ();
1632          }
1633
1634  }
1635
1636  /***********************************************************************
1637   FINDING THINGS
1638   **********************************************************************/
1639
1640 boost::shared_ptr<RegionList>
1641 Playlist::regions_at (framepos_t frame)
1642 {
1643         RegionReadLock rlock (this);
1644         return find_regions_at (frame);
1645 }
1646
1647  uint32_t
1648  Playlist::count_regions_at (framepos_t frame) const
1649  {
1650          RegionReadLock rlock (const_cast<Playlist*>(this));
1651          uint32_t cnt = 0;
1652
1653          for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1654                  if ((*i)->covers (frame)) {
1655                          cnt++;
1656                  }
1657          }
1658
1659          return cnt;
1660  }
1661
1662  boost::shared_ptr<Region>
1663  Playlist::top_region_at (framepos_t frame)
1664
1665  {
1666          RegionReadLock rlock (this);
1667          boost::shared_ptr<RegionList> rlist = find_regions_at (frame);
1668          boost::shared_ptr<Region> region;
1669
1670          if (rlist->size()) {
1671                  RegionSortByLayer cmp;
1672                  rlist->sort (cmp);
1673                  region = rlist->back();
1674          }
1675
1676          return region;
1677  }
1678
1679  boost::shared_ptr<Region>
1680  Playlist::top_unmuted_region_at (framepos_t frame)
1681
1682  {
1683          RegionReadLock rlock (this);
1684          boost::shared_ptr<RegionList> rlist = find_regions_at (frame);
1685
1686          for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1687
1688                  RegionList::iterator tmp = i;
1689                  ++tmp;
1690
1691                  if ((*i)->muted()) {
1692                          rlist->erase (i);
1693                  }
1694
1695                  i = tmp;
1696          }
1697
1698          boost::shared_ptr<Region> region;
1699
1700          if (rlist->size()) {
1701                  RegionSortByLayer cmp;
1702                  rlist->sort (cmp);
1703                  region = rlist->back();
1704          }
1705
1706          return region;
1707  }
1708
1709 boost::shared_ptr<RegionList>
1710 Playlist::find_regions_at (framepos_t frame)
1711 {
1712         /* Caller must hold lock */
1713         
1714         boost::shared_ptr<RegionList> rlist (new RegionList);
1715         
1716         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1717                 if ((*i)->covers (frame)) {
1718                         rlist->push_back (*i);
1719                 }
1720         }
1721         
1722         return rlist;
1723 }
1724
1725 boost::shared_ptr<RegionList>
1726 Playlist::regions_with_start_within (Evoral::Range<framepos_t> range)
1727 {
1728         RegionReadLock rlock (this);
1729         boost::shared_ptr<RegionList> rlist (new RegionList);
1730
1731         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1732                 if ((*i)->first_frame() >= range.from && (*i)->first_frame() <= range.to) {
1733                         rlist->push_back (*i);
1734                 }
1735         }
1736
1737         return rlist;
1738 }
1739
1740 boost::shared_ptr<RegionList>
1741 Playlist::regions_with_end_within (Evoral::Range<framepos_t> range)
1742 {
1743         RegionReadLock rlock (this);
1744         boost::shared_ptr<RegionList> rlist (new RegionList);
1745
1746         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1747                 if ((*i)->last_frame() >= range.from && (*i)->last_frame() <= range.to) {
1748                         rlist->push_back (*i);
1749                 }
1750         }
1751
1752         return rlist;
1753 }
1754
1755 /** @param start Range start.
1756  *  @param end Range end.
1757  *  @return regions which have some part within this range.
1758  */
1759 boost::shared_ptr<RegionList>
1760 Playlist::regions_touched (framepos_t start, framepos_t end)
1761 {
1762         RegionReadLock rlock (this);
1763         return regions_touched_locked (start, end);
1764 }
1765
1766 boost::shared_ptr<RegionList>
1767 Playlist::regions_touched_locked (framepos_t start, framepos_t end)
1768 {
1769         boost::shared_ptr<RegionList> rlist (new RegionList);
1770         
1771         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1772                 if ((*i)->coverage (start, end) != Evoral::OverlapNone) {
1773                         rlist->push_back (*i);
1774                 }
1775         }
1776         
1777         return rlist;
1778 }
1779
1780 framepos_t
1781 Playlist::find_next_transient (framepos_t from, int dir)
1782 {
1783         RegionReadLock rlock (this);
1784         AnalysisFeatureList points;
1785         AnalysisFeatureList these_points;
1786         
1787         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1788                 if (dir > 0) {
1789                         if ((*i)->last_frame() < from) {
1790                                 continue;
1791                         }
1792                 } else {
1793                         if ((*i)->first_frame() > from) {
1794                                 continue;
1795                         }
1796                 }
1797                 
1798                 (*i)->get_transients (these_points);
1799                 
1800                 /* add first frame, just, err, because */
1801                 
1802                 these_points.push_back ((*i)->first_frame());
1803                 
1804                 points.insert (points.end(), these_points.begin(), these_points.end());
1805                 these_points.clear ();
1806         }
1807         
1808         if (points.empty()) {
1809                 return -1;
1810         }
1811         
1812         TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1813         bool reached = false;
1814         
1815         if (dir > 0) {
1816                 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1817                         if ((*x) >= from) {
1818                                 reached = true;
1819                         }
1820                         
1821                         if (reached && (*x) > from) {
1822                                 return *x;
1823                         }
1824                 }
1825         } else {
1826                 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1827                         if ((*x) <= from) {
1828                                 reached = true;
1829                         }
1830                         
1831                         if (reached && (*x) < from) {
1832                                 return *x;
1833                         }
1834                 }
1835         }
1836         
1837         return -1;
1838 }
1839
1840 boost::shared_ptr<Region>
1841 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1842 {
1843         RegionReadLock rlock (this);
1844         boost::shared_ptr<Region> ret;
1845         framepos_t closest = max_framepos;
1846         
1847         bool end_iter = false;
1848         
1849         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1850                 
1851                 if(end_iter) break;
1852                 
1853                 frameoffset_t distance;
1854                 boost::shared_ptr<Region> r = (*i);
1855                 framepos_t pos = 0;
1856                 
1857                 switch (point) {
1858                 case Start:
1859                         pos = r->first_frame ();
1860                         break;
1861                 case End:
1862                         pos = r->last_frame ();
1863                         break;
1864                 case SyncPoint:
1865                         pos = r->sync_position ();
1866                         break;
1867                 }
1868                 
1869                 switch (dir) {
1870                 case 1: /* forwards */
1871                         
1872                         if (pos > frame) {
1873                                 if ((distance = pos - frame) < closest) {
1874                                         closest = distance;
1875                                         ret = r;
1876                                         end_iter = true;
1877                                 }
1878                         }
1879                         
1880                         break;
1881                         
1882                 default: /* backwards */
1883                         
1884                         if (pos < frame) {
1885                                 if ((distance = frame - pos) < closest) {
1886                                         closest = distance;
1887                                         ret = r;
1888                                 }
1889                         } else {
1890                                 end_iter = true;
1891                         }
1892                         
1893                         break;
1894                 }
1895         }
1896         
1897         return ret;
1898 }
1899
1900  framepos_t
1901  Playlist::find_next_region_boundary (framepos_t frame, int dir)
1902  {
1903          RegionReadLock rlock (this);
1904
1905          framepos_t closest = max_framepos;
1906          framepos_t ret = -1;
1907
1908          if (dir > 0) {
1909
1910                  for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1911
1912                          boost::shared_ptr<Region> r = (*i);
1913                          frameoffset_t distance;
1914
1915                          if (r->first_frame() > frame) {
1916
1917                                  distance = r->first_frame() - frame;
1918
1919                                  if (distance < closest) {
1920                                          ret = r->first_frame();
1921                                          closest = distance;
1922                                  }
1923                          }
1924
1925                          if (r->last_frame () > frame) {
1926
1927                                  distance = r->last_frame () - frame;
1928
1929                                  if (distance < closest) {
1930                                          ret = r->last_frame ();
1931                                          closest = distance;
1932                                  }
1933                          }
1934                  }
1935
1936          } else {
1937
1938                  for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1939
1940                          boost::shared_ptr<Region> r = (*i);
1941                          frameoffset_t distance;
1942
1943                          if (r->last_frame() < frame) {
1944
1945                                  distance = frame - r->last_frame();
1946
1947                                  if (distance < closest) {
1948                                          ret = r->last_frame();
1949                                          closest = distance;
1950                                  }
1951                          }
1952
1953                          if (r->first_frame() < frame) {
1954
1955                                  distance = frame - r->first_frame();
1956
1957                                  if (distance < closest) {
1958                                          ret = r->first_frame();
1959                                          closest = distance;
1960                                  }
1961                          }
1962                  }
1963          }
1964
1965          return ret;
1966  }
1967
1968
1969  /***********************************************************************/
1970
1971
1972
1973
1974  void
1975  Playlist::mark_session_dirty ()
1976  {
1977          if (!in_set_state && !holding_state ()) {
1978                  _session.set_dirty();
1979          }
1980  }
1981
1982  void
1983  Playlist::rdiff (vector<Command*>& cmds) const
1984  {
1985          RegionReadLock rlock (const_cast<Playlist *> (this));
1986          Stateful::rdiff (cmds);
1987  }
1988
1989  void
1990  Playlist::clear_owned_changes ()
1991  {
1992          RegionReadLock rlock (this);
1993          Stateful::clear_owned_changes ();
1994  }
1995
1996  void
1997  Playlist::update (const RegionListProperty::ChangeRecord& change)
1998  {
1999          DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
2000                                                          name(), change.added.size(), change.removed.size()));
2001
2002          freeze ();
2003          /* add the added regions */
2004          for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2005                  add_region_internal ((*i), (*i)->position());
2006          }
2007          /* remove the removed regions */
2008          for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2009                  remove_region (*i);
2010          }
2011
2012          thaw ();
2013  }
2014
2015  int
2016  Playlist::set_state (const XMLNode& node, int version)
2017  {
2018          XMLNode *child;
2019          XMLNodeList nlist;
2020          XMLNodeConstIterator niter;
2021          XMLPropertyList plist;
2022          XMLPropertyConstIterator piter;
2023          XMLProperty *prop;
2024          boost::shared_ptr<Region> region;
2025          string region_name;
2026          bool seen_region_nodes = false;
2027          int ret = 0;
2028
2029          in_set_state++;
2030
2031          if (node.name() != "Playlist") {
2032                  in_set_state--;
2033                  return -1;
2034          }
2035
2036          freeze ();
2037
2038          plist = node.properties();
2039
2040          set_id (node);
2041
2042          for (piter = plist.begin(); piter != plist.end(); ++piter) {
2043
2044                  prop = *piter;
2045
2046                  if (prop->name() == X_("name")) {
2047                          _name = prop->value();
2048                          _set_sort_id ();
2049                  } else if (prop->name() == X_("orig-diskstream-id")) {
2050                          /* XXX legacy session: fix up later */
2051                          _orig_track_id = prop->value ();
2052                  } else if (prop->name() == X_("orig-track-id")) {
2053                          _orig_track_id = prop->value ();
2054                  } else if (prop->name() == X_("frozen")) {
2055                          _frozen = string_is_affirmative (prop->value());
2056                  } else if (prop->name() == X_("combine-ops")) {
2057                          _combine_ops = atoi (prop->value());
2058                  }
2059          }
2060
2061          clear (true);
2062
2063          nlist = node.children();
2064
2065          for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2066
2067                  child = *niter;
2068
2069                  if (child->name() == "Region") {
2070
2071                          seen_region_nodes = true;
2072
2073                          if ((prop = child->property ("id")) == 0) {
2074                                  error << _("region state node has no ID, ignored") << endmsg;
2075                                  continue;
2076                          }
2077
2078                          ID id = prop->value ();
2079
2080                          if ((region = region_by_id (id))) {
2081
2082                                  region->suspend_property_changes ();
2083
2084                                  if (region->set_state (*child, version)) {
2085                                          region->resume_property_changes ();
2086                                          continue;
2087                                  }
2088
2089                          } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2090                                  region->suspend_property_changes ();
2091                          } else {
2092                                  error << _("Playlist: cannot create region from XML") << endmsg;
2093                                 return -1;
2094                         }
2095
2096                          {
2097                                  RegionWriteLock rlock (this);
2098                                  add_region_internal (region, region->position());
2099                          }
2100                         
2101                         region->resume_property_changes ();
2102
2103                 }
2104         }
2105
2106         if (seen_region_nodes && regions.empty()) {
2107                 ret = -1;
2108         } else {
2109
2110                 /* update dependents, which was not done during add_region_internal
2111                    due to in_set_state being true
2112                 */
2113                 
2114                 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2115                         check_crossfades ((*r)->range ());
2116                 }
2117         }
2118                 
2119         thaw ();
2120         notify_contents_changed ();
2121
2122         in_set_state--;
2123         first_set_state = false;
2124
2125         return ret;
2126 }
2127
2128 XMLNode&
2129 Playlist::get_state()
2130 {
2131         return state (true);
2132 }
2133
2134 XMLNode&
2135 Playlist::get_template()
2136 {
2137         return state (false);
2138 }
2139
2140 /** @param full_state true to include regions in the returned state, otherwise false.
2141  */
2142 XMLNode&
2143 Playlist::state (bool full_state)
2144 {
2145         XMLNode *node = new XMLNode (X_("Playlist"));
2146         char buf[64];
2147
2148         node->add_property (X_("id"), id().to_s());
2149         node->add_property (X_("name"), _name);
2150         node->add_property (X_("type"), _type.to_string());
2151
2152         _orig_track_id.print (buf, sizeof (buf));
2153         node->add_property (X_("orig-track-id"), buf);
2154         node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2155
2156         if (full_state) {
2157                 RegionReadLock rlock (this);
2158
2159                 snprintf (buf, sizeof (buf), "%u", _combine_ops);
2160                 node->add_property ("combine-ops", buf);
2161
2162                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2163                         node->add_child_nocopy ((*i)->get_state());
2164                 }
2165         }
2166
2167         if (_extra_xml) {
2168                 node->add_child_copy (*_extra_xml);
2169         }
2170
2171         return *node;
2172 }
2173
2174 bool
2175 Playlist::empty() const
2176 {
2177         RegionReadLock rlock (const_cast<Playlist *>(this));
2178         return regions.empty();
2179 }
2180
2181 uint32_t
2182 Playlist::n_regions() const
2183 {
2184         RegionReadLock rlock (const_cast<Playlist *>(this));
2185         return regions.size();
2186 }
2187
2188 pair<framepos_t, framepos_t>
2189 Playlist::get_extent () const
2190 {
2191         RegionReadLock rlock (const_cast<Playlist *>(this));
2192         return _get_extent ();
2193 }
2194
2195 pair<framepos_t, framepos_t>
2196 Playlist::_get_extent () const
2197 {
2198         pair<framepos_t, framepos_t> ext (max_framepos, 0);
2199
2200         if (regions.empty()) {
2201                 ext.first = 0;
2202                 return ext;
2203         }
2204
2205         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2206                 pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2207                 if (e.first < ext.first) {
2208                         ext.first = e.first;
2209                 }
2210                 if (e.second > ext.second) {
2211                         ext.second = e.second;
2212                 }
2213         }
2214
2215         return ext;
2216 }
2217
2218 string
2219 Playlist::bump_name (string name, Session &session)
2220 {
2221         string newname = name;
2222
2223         do {
2224                 newname = bump_name_once (newname, '.');
2225         } while (session.playlists->by_name (newname)!=NULL);
2226
2227         return newname;
2228 }
2229
2230
2231 layer_t
2232 Playlist::top_layer() const
2233 {
2234         RegionReadLock rlock (const_cast<Playlist *> (this));
2235         layer_t top = 0;
2236
2237         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2238                 top = max (top, (*i)->layer());
2239         }
2240         return top;
2241 }
2242
2243 void
2244 Playlist::set_edit_mode (EditMode mode)
2245 {
2246         _edit_mode = mode;
2247 }
2248
2249 struct RelayerSort {
2250         bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
2251                 return a->layering_index() < b->layering_index();
2252         }
2253 };
2254
2255 /** Set a new layer for a region.  This adjusts the layering indices of all
2256  *  regions in the playlist to put the specified region in the appropriate
2257  *  place.  The actual layering will be fixed up when relayer() happens.
2258  */
2259
2260 void
2261 Playlist::set_layer (boost::shared_ptr<Region> region, double new_layer)
2262 {
2263         /* Remove the layer we are setting from our region list, and sort it */
2264         RegionList copy = regions.rlist();
2265         copy.remove (region);
2266         copy.sort (RelayerSort ());
2267
2268         /* Put region back in the right place */
2269         RegionList::iterator i = copy.begin();
2270         while (i != copy.end ()) {
2271                 if ((*i)->layer() > new_layer) {
2272                         break;
2273                 }
2274                 ++i;
2275         }
2276         
2277         copy.insert (i, region);
2278
2279         setup_layering_indices (copy);
2280 }
2281
2282 void
2283 Playlist::setup_layering_indices (RegionList const & regions)
2284 {
2285         uint64_t j = 0;
2286         list<Evoral::Range<framepos_t> > xf;
2287
2288         for (RegionList::const_iterator k = regions.begin(); k != regions.end(); ++k) {
2289                 (*k)->set_layering_index (j++);
2290         }
2291 }
2292
2293 /** Take the layering indices of each of our regions, compute the layers
2294  *  that they should be on, and write the layers back to the regions.
2295  */
2296 void
2297 Playlist::relayer ()
2298 {
2299         /* never compute layers when setting from XML */
2300
2301         if (in_set_state) {
2302                 return;
2303         }
2304
2305         /* Build up a new list of regions on each layer, stored in a set of lists
2306            each of which represent some period of time on some layer.  The idea
2307            is to avoid having to search the entire region list to establish whether
2308            each region overlaps another */
2309
2310         /* how many pieces to divide this playlist's time up into */
2311         int const divisions = 512;
2312
2313         /* find the start and end positions of the regions on this playlist */
2314         framepos_t start = INT64_MAX;
2315         framepos_t end = 0;
2316         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2317                 start = min (start, (*i)->position());
2318                 end = max (end, (*i)->position() + (*i)->length());
2319         }
2320
2321         /* hence the size of each time division */
2322         double const division_size = (end - start) / double (divisions);
2323
2324         vector<vector<RegionList> > layers;
2325         layers.push_back (vector<RegionList> (divisions));
2326
2327         /* Sort our regions into layering index order */
2328         RegionList copy = regions.rlist();
2329         copy.sort (RelayerSort ());
2330
2331         DEBUG_TRACE (DEBUG::Layering, "relayer() using:\n");
2332         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2333                 DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1 %2\n", (*i)->name(), (*i)->layering_index()));
2334         }
2335
2336         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2337
2338                 /* find the time divisions that this region covers; if there are no regions on the list,
2339                    division_size will equal 0 and in this case we'll just say that
2340                    start_division = end_division = 0.
2341                 */
2342                 int start_division = 0;
2343                 int end_division = 0;
2344
2345                 if (division_size > 0) {
2346                         start_division = floor ( ((*i)->position() - start) / division_size);
2347                         end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2348                         if (end_division == divisions) {
2349                                 end_division--;
2350                         }
2351                 }
2352
2353                 assert (divisions == 0 || end_division < divisions);
2354
2355                 /* find the lowest layer that this region can go on */
2356                 size_t j = layers.size();
2357                 while (j > 0) {
2358                         /* try layer j - 1; it can go on if it overlaps no other region
2359                            that is already on that layer
2360                         */
2361
2362                         bool overlap = false;
2363                         for (int k = start_division; k <= end_division; ++k) {
2364                                 RegionList::iterator l = layers[j-1][k].begin ();
2365                                 while (l != layers[j-1][k].end()) {
2366                                         if ((*l)->overlap_equivalent (*i)) {
2367                                                 overlap = true;
2368                                                 break;
2369                                         }
2370                                         l++;
2371                                 }
2372
2373                                 if (overlap) {
2374                                         break;
2375                                 }
2376                         }
2377
2378                         if (overlap) {
2379                                 /* overlap, so we must use layer j */
2380                                 break;
2381                         }
2382
2383                         --j;
2384                 }
2385
2386                 if (j == layers.size()) {
2387                         /* we need a new layer for this region */
2388                         layers.push_back (vector<RegionList> (divisions));
2389                 }
2390
2391                 /* put a reference to this region in each of the divisions that it exists in */
2392                 for (int k = start_division; k <= end_division; ++k) {
2393                         layers[j][k].push_back (*i);
2394                 }
2395
2396                 (*i)->set_layer (j);
2397         }
2398
2399         /* It's a little tricky to know when we could avoid calling this; e.g. if we are
2400            relayering because we just removed the only region on the top layer, nothing will
2401            appear to have changed, but the StreamView must still sort itself out.  We could
2402            probably keep a note of the top layer last time we relayered, and check that,
2403            but premature optimisation &c...
2404         */
2405         notify_layering_changed ();
2406
2407         /* This relayer() may have been called as a result of a region removal, in which
2408            case we need to setup layering indices to account for the one that has just
2409            gone away.
2410         */
2411         setup_layering_indices (copy);
2412 }
2413
2414 void
2415 Playlist::raise_region (boost::shared_ptr<Region> region)
2416 {
2417         set_layer (region, region->layer() + 1.5);
2418         relayer ();
2419         check_crossfades (region->range ());
2420 }
2421
2422 void
2423 Playlist::lower_region (boost::shared_ptr<Region> region)
2424 {
2425         set_layer (region, region->layer() - 1.5);
2426         relayer ();
2427         check_crossfades (region->range ());
2428 }
2429
2430 void
2431 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2432 {
2433         set_layer (region, DBL_MAX);
2434         relayer ();
2435         check_crossfades (region->range ());
2436 }
2437
2438 void
2439 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2440 {
2441         set_layer (region, -0.5);
2442         relayer ();
2443         check_crossfades (region->range ());
2444 }
2445
2446 void
2447 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2448 {
2449         RegionList::iterator i;
2450         bool moved = false;
2451
2452         _nudging = true;
2453
2454         {
2455                 RegionWriteLock rlock (const_cast<Playlist *> (this));
2456
2457                 for (i = regions.begin(); i != regions.end(); ++i) {
2458
2459                         if ((*i)->position() >= start) {
2460
2461                                 framepos_t new_pos;
2462
2463                                 if (forwards) {
2464
2465                                         if ((*i)->last_frame() > max_framepos - distance) {
2466                                                 new_pos = max_framepos - (*i)->length();
2467                                         } else {
2468                                                 new_pos = (*i)->position() + distance;
2469                                         }
2470
2471                                 } else {
2472
2473                                         if ((*i)->position() > distance) {
2474                                                 new_pos = (*i)->position() - distance;
2475                                         } else {
2476                                                 new_pos = 0;
2477                                         }
2478                                 }
2479
2480                                 (*i)->set_position (new_pos);
2481                                 moved = true;
2482                         }
2483                 }
2484         }
2485
2486         if (moved) {
2487                 _nudging = false;
2488                 notify_contents_changed ();
2489         }
2490
2491 }
2492
2493 bool
2494 Playlist::uses_source (boost::shared_ptr<const Source> src) const
2495 {
2496         RegionReadLock rlock (const_cast<Playlist*> (this));
2497
2498         for (set<boost::shared_ptr<Region> >::iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
2499                 if ((*r)->uses_source (src)) {
2500                         return true;
2501                 }
2502         }
2503
2504         return false;
2505 }
2506
2507 boost::shared_ptr<Region>
2508 Playlist::find_region (const ID& id) const
2509 {
2510         RegionReadLock rlock (const_cast<Playlist*> (this));
2511
2512         /* searches all regions currently in use by the playlist */
2513
2514         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2515                 if ((*i)->id() == id) {
2516                         return *i;
2517                 }
2518         }
2519
2520         return boost::shared_ptr<Region> ();
2521 }
2522
2523 uint32_t
2524 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2525 {
2526         RegionReadLock rlock (const_cast<Playlist*> (this));
2527         uint32_t cnt = 0;
2528
2529         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2530                 if ((*i) == r) {
2531                         cnt++;
2532                 }
2533         }
2534
2535         return cnt;
2536 }
2537
2538 boost::shared_ptr<Region>
2539 Playlist::region_by_id (const ID& id) const
2540 {
2541         /* searches all regions ever added to this playlist */
2542
2543         for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2544                 if ((*i)->id() == id) {
2545                         return *i;
2546                 }
2547         }
2548         return boost::shared_ptr<Region> ();
2549 }
2550
2551 void
2552 Playlist::dump () const
2553 {
2554         boost::shared_ptr<Region> r;
2555
2556         cerr << "Playlist \"" << _name << "\" " << endl
2557              << regions.size() << " regions "
2558              << endl;
2559
2560         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2561                 r = *i;
2562                 cerr << "  " << r->name() << " ["
2563                      << r->start() << "+" << r->length()
2564                      << "] at "
2565                      << r->position()
2566                      << " on layer "
2567                      << r->layer ()
2568                      << endl;
2569         }
2570 }
2571
2572 void
2573 Playlist::set_frozen (bool yn)
2574 {
2575         _frozen = yn;
2576 }
2577
2578 void
2579 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2580 {
2581         bool moved = false;
2582
2583         if (region->locked()) {
2584                 return;
2585         }
2586
2587         _shuffling = true;
2588
2589         {
2590                 RegionWriteLock rlock (const_cast<Playlist*> (this));
2591
2592
2593                 if (dir > 0) {
2594
2595                         RegionList::iterator next;
2596
2597                         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2598                                 if ((*i) == region) {
2599                                         next = i;
2600                                         ++next;
2601
2602                                         if (next != regions.end()) {
2603
2604                                                 if ((*next)->locked()) {
2605                                                         break;
2606                                                 }
2607
2608                                                 framepos_t new_pos;
2609
2610                                                 if ((*next)->position() != region->last_frame() + 1) {
2611                                                         /* they didn't used to touch, so after shuffle,
2612                                                            just have them swap positions.
2613                                                         */
2614                                                         new_pos = (*next)->position();
2615                                                 } else {
2616                                                         /* they used to touch, so after shuffle,
2617                                                            make sure they still do. put the earlier
2618                                                            region where the later one will end after
2619                                                            it is moved.
2620                                                         */
2621                                                         new_pos = region->position() + (*next)->length();
2622                                                 }
2623
2624                                                 (*next)->set_position (region->position());
2625                                                 region->set_position (new_pos);
2626
2627                                                 /* avoid a full sort */
2628
2629                                                 regions.erase (i); // removes the region from the list */
2630                                                 next++;
2631                                                 regions.insert (next, region); // adds it back after next
2632
2633                                                 moved = true;
2634                                         }
2635                                         break;
2636                                 }
2637                         }
2638                 } else {
2639
2640                         RegionList::iterator prev = regions.end();
2641
2642                         for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2643                                 if ((*i) == region) {
2644
2645                                         if (prev != regions.end()) {
2646
2647                                                 if ((*prev)->locked()) {
2648                                                         break;
2649                                                 }
2650
2651                                                 framepos_t new_pos;
2652                                                 if (region->position() != (*prev)->last_frame() + 1) {
2653                                                         /* they didn't used to touch, so after shuffle,
2654                                                            just have them swap positions.
2655                                                         */
2656                                                         new_pos = region->position();
2657                                                 } else {
2658                                                         /* they used to touch, so after shuffle,
2659                                                            make sure they still do. put the earlier
2660                                                            one where the later one will end after
2661                                                         */
2662                                                         new_pos = (*prev)->position() + region->length();
2663                                                 }
2664
2665                                                 region->set_position ((*prev)->position());
2666                                                 (*prev)->set_position (new_pos);
2667
2668                                                 /* avoid a full sort */
2669
2670                                                 regions.erase (i); // remove region
2671                                                 regions.insert (prev, region); // insert region before prev
2672
2673                                                 moved = true;
2674                                         }
2675
2676                                         break;
2677                                 }
2678                         }
2679                 }
2680         }
2681
2682         _shuffling = false;
2683
2684         if (moved) {
2685
2686                 relayer ();
2687                 notify_contents_changed();
2688         }
2689
2690 }
2691
2692 bool
2693 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2694 {
2695         RegionReadLock rlock (const_cast<Playlist*> (this));
2696
2697         if (regions.size() > 1) {
2698                 return true;
2699         }
2700
2701         return false;
2702 }
2703
2704 void
2705 Playlist::update_after_tempo_map_change ()
2706 {
2707         RegionWriteLock rlock (const_cast<Playlist*> (this));
2708         RegionList copy (regions.rlist());
2709
2710         freeze ();
2711
2712         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2713                 (*i)->update_after_tempo_map_change ();
2714         }
2715
2716         thaw ();
2717 }
2718
2719 void
2720 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2721 {
2722         RegionWriteLock rl (this, false);
2723         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2724                 s (*i);
2725         }
2726 }
2727
2728 bool
2729 Playlist::has_region_at (framepos_t const p) const
2730 {
2731         RegionReadLock (const_cast<Playlist *> (this));
2732
2733         RegionList::const_iterator i = regions.begin ();
2734         while (i != regions.end() && !(*i)->covers (p)) {
2735                 ++i;
2736         }
2737
2738         return (i != regions.end());
2739 }
2740
2741 /** Remove any region that uses a given source */
2742 void
2743 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
2744 {
2745         RegionWriteLock rl (this);
2746
2747         RegionList::iterator i = regions.begin();
2748         while (i != regions.end()) {
2749                 RegionList::iterator j = i;
2750                 ++j;
2751
2752                 if ((*i)->uses_source (s)) {
2753                         remove_region_internal (*i);
2754                 }
2755
2756                 i = j;
2757         }
2758 }
2759
2760 /** Look from a session frame time and find the start time of the next region
2761  *  which is on the top layer of this playlist.
2762  *  @param t Time to look from.
2763  *  @return Position of next top-layered region, or max_framepos if there isn't one.
2764  */
2765 framepos_t
2766 Playlist::find_next_top_layer_position (framepos_t t) const
2767 {
2768         RegionReadLock rlock (const_cast<Playlist *> (this));
2769
2770         layer_t const top = top_layer ();
2771
2772         RegionList copy = regions.rlist ();
2773         copy.sort (RegionSortByPosition ());
2774
2775         for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
2776                 if ((*i)->position() >= t && (*i)->layer() == top) {
2777                         return (*i)->position();
2778                 }
2779         }
2780
2781         return max_framepos;
2782 }
2783
2784 boost::shared_ptr<Region>
2785 Playlist::combine (const RegionList& r)
2786 {
2787         PropertyList plist;
2788         uint32_t channels = 0;
2789         uint32_t layer = 0;
2790         framepos_t earliest_position = max_framepos;
2791         vector<TwoRegions> old_and_new_regions;
2792         vector<boost::shared_ptr<Region> > originals;
2793         vector<boost::shared_ptr<Region> > copies;
2794         string parent_name;
2795         string child_name;
2796         uint32_t max_level = 0;
2797
2798         /* find the maximum depth of all the regions we're combining */
2799
2800         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
2801                 max_level = max (max_level, (*i)->max_source_level());
2802         }
2803
2804         parent_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, true);
2805         child_name = RegionFactory::compound_region_name (name(), combine_ops(), max_level, false);
2806
2807         boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, parent_name, true);
2808
2809         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
2810                 earliest_position = min (earliest_position, (*i)->position());
2811         }
2812
2813         /* enable this so that we do not try to create xfades etc. as we add
2814          * regions
2815          */
2816
2817         pl->in_partition = true;
2818
2819         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
2820
2821                 /* copy the region */
2822
2823                 boost::shared_ptr<Region> original_region = (*i);
2824                 boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
2825
2826                 old_and_new_regions.push_back (TwoRegions (original_region,copied_region));
2827                 originals.push_back (original_region);
2828                 copies.push_back (copied_region);
2829
2830                 RegionFactory::add_compound_association (original_region, copied_region);
2831
2832                 /* make position relative to zero */
2833
2834                 pl->add_region (copied_region, original_region->position() - earliest_position);
2835
2836                 /* use the maximum number of channels for any region */
2837
2838                 channels = max (channels, original_region->n_channels());
2839
2840                 /* it will go above the layer of the highest existing region */
2841
2842                 layer = max (layer, original_region->layer());
2843         }
2844
2845         pl->in_partition = false;
2846
2847         pre_combine (copies);
2848
2849         /* now create a new PlaylistSource for each channel in the new playlist */
2850
2851         SourceList sources;
2852         pair<framepos_t,framepos_t> extent = pl->get_extent();
2853
2854         for (uint32_t chn = 0; chn < channels; ++chn) {
2855                 sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, id(), parent_name, chn, 0, extent.second, false, false));
2856
2857         }
2858
2859         /* now a new whole-file region using the list of sources */
2860
2861         plist.add (Properties::start, 0);
2862         plist.add (Properties::length, extent.second);
2863         plist.add (Properties::name, parent_name);
2864         plist.add (Properties::whole_file, true);
2865
2866         boost::shared_ptr<Region> parent_region = RegionFactory::create (sources, plist, true);
2867
2868         /* now the non-whole-file region that we will actually use in the
2869          * playlist
2870          */
2871
2872         plist.clear ();
2873         plist.add (Properties::start, 0);
2874         plist.add (Properties::length, extent.second);
2875         plist.add (Properties::name, child_name);
2876         plist.add (Properties::layer, layer+1);
2877
2878         boost::shared_ptr<Region> compound_region = RegionFactory::create (parent_region, plist, true);
2879
2880         /* remove all the selected regions from the current playlist
2881          */
2882
2883         freeze ();
2884
2885         for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
2886                 remove_region (*i);
2887         }
2888
2889         /* do type-specific stuff with the originals and the new compound
2890            region
2891         */
2892
2893         post_combine (originals, compound_region);
2894
2895         /* add the new region at the right location */
2896
2897         add_region (compound_region, earliest_position);
2898
2899         _combine_ops++;
2900
2901         thaw ();
2902
2903         return compound_region;
2904 }
2905
2906 void
2907 Playlist::uncombine (boost::shared_ptr<Region> target)
2908 {
2909         boost::shared_ptr<PlaylistSource> pls;
2910         boost::shared_ptr<const Playlist> pl;
2911         vector<boost::shared_ptr<Region> > originals;
2912         vector<TwoRegions> old_and_new_regions;
2913
2914         // (1) check that its really a compound region
2915
2916         if ((pls = boost::dynamic_pointer_cast<PlaylistSource>(target->source (0))) == 0) {
2917                 return;
2918         }
2919
2920         pl = pls->playlist();
2921
2922         framepos_t adjusted_start = 0; // gcc isn't smart enough
2923         framepos_t adjusted_end = 0;   // gcc isn't smart enough
2924
2925         /* the leftmost (earliest) edge of the compound region
2926            starts at zero in its source, or larger if it
2927            has been trimmed or content-scrolled.
2928
2929            the rightmost (latest) edge of the compound region
2930            relative to its source is the starting point plus
2931            the length of the region.
2932         */
2933
2934         // (2) get all the original regions
2935
2936         const RegionList& rl (pl->region_list().rlist());
2937         RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
2938         frameoffset_t move_offset = 0;
2939
2940         /* there are two possibilities here:
2941            1) the playlist that the playlist source was based on
2942            is us, so just add the originals (which belonged to
2943            us anyway) back in the right place.
2944
2945            2) the playlist that the playlist source was based on
2946            is NOT us, so we need to make copies of each of
2947            the original regions that we find, and add them
2948            instead.
2949         */
2950         bool same_playlist = (pls->original() == id());
2951
2952         for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
2953
2954                 boost::shared_ptr<Region> current (*i);
2955
2956                 RegionFactory::CompoundAssociations::iterator ca = cassocs.find (*i);
2957
2958                 if (ca == cassocs.end()) {
2959                         continue;
2960                 }
2961
2962                 boost::shared_ptr<Region> original (ca->second);
2963                 bool modified_region;
2964
2965                 if (i == rl.begin()) {
2966                         move_offset = (target->position() - original->position()) - target->start();
2967                         adjusted_start = original->position() + target->start();
2968                         adjusted_end = adjusted_start + target->length();
2969                 }
2970
2971                 if (!same_playlist) {
2972                         framepos_t pos = original->position();
2973                         /* make a copy, but don't announce it */
2974                         original = RegionFactory::create (original, false);
2975                         /* the pure copy constructor resets position() to zero,
2976                            so fix that up.
2977                         */
2978                         original->set_position (pos);
2979                 }
2980
2981                 /* check to see how the original region (in the
2982                  * playlist before compounding occured) overlaps
2983                  * with the new state of the compound region.
2984                  */
2985
2986                 original->clear_changes ();
2987                 modified_region = false;
2988
2989                 switch (original->coverage (adjusted_start, adjusted_end)) {
2990                 case Evoral::OverlapNone:
2991                         /* original region does not cover any part
2992                            of the current state of the compound region
2993                         */
2994                         continue;
2995
2996                 case Evoral::OverlapInternal:
2997                         /* overlap is just a small piece inside the
2998                          * original so trim both ends
2999                          */
3000                         original->trim_to (adjusted_start, adjusted_end - adjusted_start);
3001                         modified_region = true;
3002                         break;
3003
3004                 case Evoral::OverlapExternal:
3005                         /* overlap fully covers original, so leave it
3006                            as is
3007                         */
3008                         break;
3009
3010                 case Evoral::OverlapEnd:
3011                         /* overlap starts within but covers end,
3012                            so trim the front of the region
3013                         */
3014                         original->trim_front (adjusted_start);
3015                         modified_region = true;
3016                         break;
3017
3018                 case Evoral::OverlapStart:
3019                         /* overlap covers start but ends within, so
3020                          * trim the end of the region.
3021                          */
3022                         original->trim_end (adjusted_end);
3023                         modified_region = true;
3024                         break;
3025                 }
3026
3027                 if (move_offset) {
3028                         /* fix the position to match any movement of the compound region.
3029                          */
3030                         original->set_position (original->position() + move_offset);
3031                         modified_region = true;
3032                 }
3033
3034                 if (modified_region) {
3035                         _session.add_command (new StatefulDiffCommand (original));
3036                 }
3037
3038                 /* and add to the list of regions waiting to be
3039                  * re-inserted
3040                  */
3041
3042                 originals.push_back (original);
3043                 old_and_new_regions.push_back (TwoRegions (*i, original));
3044         }
3045
3046         pre_uncombine (originals, target);
3047
3048         in_partition = true;
3049         freeze ();
3050
3051         // (3) remove the compound region
3052
3053         remove_region (target);
3054
3055         // (4) add the constituent regions
3056
3057         for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
3058                 add_region ((*i), (*i)->position());
3059         }
3060
3061         in_partition = false;
3062         thaw ();
3063 }
3064
3065 uint32_t
3066 Playlist::max_source_level () const
3067 {
3068         RegionReadLock rlock (const_cast<Playlist *> (this));
3069         uint32_t lvl = 0;
3070
3071         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
3072                 lvl = max (lvl, (*i)->max_source_level());
3073         }
3074
3075         return lvl;
3076 }
3077
3078 void
3079 Playlist::set_orig_track_id (const PBD::ID& id)
3080 {
3081         _orig_track_id = id;
3082 }
3083
3084 /** Take a list of ranges, coalesce any that can be coalesced, then call
3085  *  check_crossfades for each one.
3086  */
3087 void
3088 Playlist::coalesce_and_check_crossfades (list<Evoral::Range<framepos_t> > ranges)
3089 {
3090         /* XXX: it's a shame that this coalesce algorithm also exists in
3091            TimeSelection::consolidate().
3092         */
3093
3094         /* XXX: xfade: this is implemented in Evoral::RangeList */
3095
3096 restart:
3097         for (list<Evoral::Range<framepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
3098                 for (list<Evoral::Range<framepos_t> >::iterator j = ranges.begin(); j != ranges.end(); ++j) {
3099
3100                         if (i == j) {
3101                                 continue;
3102                         }
3103
3104                         if (Evoral::coverage (i->from, i->to, j->from, j->to) != Evoral::OverlapNone) {
3105                                 i->from = min (i->from, j->from);
3106                                 i->to = max (i->to, j->to);
3107                                 ranges.erase (j);
3108                                 goto restart;
3109                         }
3110                 }
3111         }
3112
3113         for (list<Evoral::Range<framepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
3114                 check_crossfades (*i);
3115         }
3116 }