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