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