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