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