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