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