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