Add panners and libtimecode to library path.
[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         cerr << "Playlist: region added at " << position << endl;
781
782         possibly_splice_unlocked (position, region->length(), region);
783
784         cerr << "Playlist: post-splice, region @  " << region->position() << endl;
785
786         if (!holding_state ()) {
787                 /* layers get assigned from XML state, and are not reset during undo/redo */
788                 relayer ();
789         }
790
791         /* we need to notify the existence of new region before checking dependents. Ick. */
792
793         notify_region_added (region);
794
795         if (!holding_state ()) {
796
797                 check_dependents (region, false);
798
799                 if (old_length != _get_extent().second) {
800                         notify_length_changed ();
801                 }
802         }
803
804         region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
805
806         return true;
807 }
808
809 void
810 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
811 {
812         RegionLock rlock (this);
813
814         bool old_sp = _splicing;
815         _splicing = true;
816
817         remove_region_internal (old);
818         add_region_internal (newr, pos);
819
820         _splicing = old_sp;
821
822         possibly_splice_unlocked (pos, old->length() - newr->length());
823 }
824
825 void
826 Playlist::remove_region (boost::shared_ptr<Region> region)
827 {
828         RegionLock rlock (this);
829         remove_region_internal (region);
830 }
831
832 int
833 Playlist::remove_region_internal (boost::shared_ptr<Region> region)
834 {
835         RegionList::iterator i;
836         framecnt_t old_length = 0;
837         int ret = -1;
838
839         if (!holding_state()) {
840                 old_length = _get_extent().second;
841         }
842
843         if (!in_set_state) {
844                 /* unset playlist */
845                 region->set_playlist (boost::weak_ptr<Playlist>());
846         }
847
848         /* XXX should probably freeze here .... */
849
850         for (i = regions.begin(); i != regions.end(); ++i) {
851                 if (*i == region) {
852
853                         framepos_t pos = (*i)->position();
854                         framecnt_t distance = (*i)->length();
855
856                         regions.erase (i);
857
858                         possibly_splice_unlocked (pos, -distance);
859
860                         if (!holding_state ()) {
861                                 relayer ();
862                                 remove_dependents (region);
863
864                                 if (old_length != _get_extent().second) {
865                                         notify_length_changed ();
866                                 }
867                         }
868
869                         notify_region_removed (region);
870                         ret = 0;
871                         break;
872                 }
873         }
874
875         return -1;
876 }
877
878 void
879 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
880 {
881         if (Config->get_use_overlap_equivalency()) {
882                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
883                         if ((*i)->overlap_equivalent (other)) {
884                                 results.push_back ((*i));
885                         }
886                 }
887         } else {
888                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
889                         if ((*i)->equivalent (other)) {
890                                 results.push_back ((*i));
891                         }
892                 }
893         }
894 }
895
896 void
897 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
898 {
899         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
900
901                 if ((*i) && (*i)->region_list_equivalent (other)) {
902                         results.push_back (*i);
903                 }
904         }
905 }
906
907 void
908 Playlist::partition (framepos_t start, framepos_t end, bool cut)
909 {
910         RegionList thawlist;
911
912         partition_internal (start, end, cut, thawlist);
913
914         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
915                 (*i)->resume_property_changes ();
916         }
917 }
918
919 void
920 Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
921 {
922         RegionList new_regions;
923
924         {
925                 RegionLock rlock (this);
926
927                 boost::shared_ptr<Region> region;
928                 boost::shared_ptr<Region> current;
929                 string new_name;
930                 RegionList::iterator tmp;
931                 OverlapType overlap;
932                 framepos_t pos1, pos2, pos3, pos4;
933
934                 in_partition = true;
935
936                 /* need to work from a copy, because otherwise the regions we add during the process
937                    get operated on as well.
938                 */
939
940                 RegionList copy = regions.rlist();
941
942                 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
943
944                         tmp = i;
945                         ++tmp;
946
947                         current = *i;
948
949                         if (current->first_frame() >= start && current->last_frame() < end) {
950
951                                 if (cutting) {
952                                         remove_region_internal (current);
953                                 }
954
955                                 continue;
956                         }
957
958                         /* coverage will return OverlapStart if the start coincides
959                            with the end point. we do not partition such a region,
960                            so catch this special case.
961                         */
962
963                         if (current->first_frame() >= end) {
964                                 continue;
965                         }
966
967                         if ((overlap = current->coverage (start, end)) == OverlapNone) {
968                                 continue;
969                         }
970
971                         pos1 = current->position();
972                         pos2 = start;
973                         pos3 = end;
974                         pos4 = current->last_frame();
975
976                         if (overlap == OverlapInternal) {
977                                 /* split: we need 3 new regions, the front, middle and end.
978                                    cut:   we need 2 regions, the front and end.
979                                 */
980
981                                 /*
982                                          start                 end
983                           ---------------*************************------------
984                                          P1  P2              P3  P4
985                           SPLIT:
986                           ---------------*****++++++++++++++++====------------
987                           CUT
988                           ---------------*****----------------====------------
989
990                                 */
991
992                                 if (!cutting) {
993                                         /* "middle" ++++++ */
994
995                                         RegionFactory::region_name (new_name, current->name(), false);
996
997                                         PropertyList plist;
998                                         
999                                         plist.add (Properties::start, current->start() + (pos2 - pos1));
1000                                         plist.add (Properties::length, pos3 - pos2);
1001                                         plist.add (Properties::name, new_name);
1002                                         plist.add (Properties::layer, regions.size());
1003                                         plist.add (Properties::automatic, true);
1004                                         plist.add (Properties::left_of_split, true);
1005                                         plist.add (Properties::right_of_split, true);
1006
1007                                         region = RegionFactory::create (current, plist);
1008                                         add_region_internal (region, start);
1009                                         new_regions.push_back (region);
1010                                 }
1011
1012                                 /* "end" ====== */
1013
1014                                 RegionFactory::region_name (new_name, current->name(), false);
1015
1016                                 PropertyList plist;
1017                                 
1018                                 plist.add (Properties::start, current->start() + (pos3 - pos1));
1019                                 plist.add (Properties::length, pos4 - pos3);
1020                                 plist.add (Properties::name, new_name);
1021                                 plist.add (Properties::layer, regions.size());
1022                                 plist.add (Properties::automatic, true);
1023                                 plist.add (Properties::right_of_split, true);
1024                                 
1025                                 region = RegionFactory::create (current, plist);
1026
1027                                 add_region_internal (region, end);
1028                                 new_regions.push_back (region);
1029
1030                                 /* "front" ***** */
1031
1032                                 current->suspend_property_changes ();
1033                                 thawlist.push_back (current);
1034                                 current->cut_end (pos2 - 1, this);
1035
1036                         } else if (overlap == OverlapEnd) {
1037
1038                                 /*
1039                                                               start           end
1040                                     ---------------*************************------------
1041                                                    P1           P2         P4   P3
1042                                     SPLIT:
1043                                     ---------------**************+++++++++++------------
1044                                     CUT:
1045                                     ---------------**************-----------------------
1046                                 */
1047
1048                                 if (!cutting) {
1049
1050                                         /* end +++++ */
1051
1052                                         RegionFactory::region_name (new_name, current->name(), false);
1053                                         
1054                                         PropertyList plist;
1055                                         
1056                                         plist.add (Properties::start, current->start() + (pos2 - pos1));
1057                                         plist.add (Properties::length, pos4 - pos2);
1058                                         plist.add (Properties::name, new_name);
1059                                         plist.add (Properties::layer, regions.size());
1060                                         plist.add (Properties::automatic, true);
1061                                         plist.add (Properties::left_of_split, true);
1062
1063                                         region = RegionFactory::create (current, plist);
1064
1065                                         add_region_internal (region, start);
1066                                         new_regions.push_back (region);
1067                                 }
1068
1069                                 /* front ****** */
1070
1071                                 current->suspend_property_changes ();
1072                                 thawlist.push_back (current);
1073                                 current->cut_end (pos2 - 1, this);
1074
1075                         } else if (overlap == OverlapStart) {
1076
1077                                 /* split: we need 2 regions: the front and the end.
1078                                    cut: just trim current to skip the cut area
1079                                 */
1080
1081                                 /*
1082                                                         start           end
1083                                     ---------------*************************------------
1084                                        P2          P1 P3                   P4
1085
1086                                     SPLIT:
1087                                     ---------------****+++++++++++++++++++++------------
1088                                     CUT:
1089                                     -------------------*********************------------
1090
1091                                 */
1092
1093                                 if (!cutting) {
1094                                         /* front **** */
1095                                         RegionFactory::region_name (new_name, current->name(), false);
1096
1097                                         PropertyList plist;
1098                                         
1099                                         plist.add (Properties::start, current->start());
1100                                         plist.add (Properties::length, pos3 - pos1);
1101                                         plist.add (Properties::name, new_name);
1102                                         plist.add (Properties::layer, regions.size());
1103                                         plist.add (Properties::automatic, true);
1104                                         plist.add (Properties::right_of_split, true);
1105
1106                                         region = RegionFactory::create (current, plist);
1107
1108                                         add_region_internal (region, pos1);
1109                                         new_regions.push_back (region);
1110                                 }
1111
1112                                 /* end */
1113
1114                                 current->suspend_property_changes ();
1115                                 thawlist.push_back (current);
1116                                 current->trim_front (pos3, this);
1117                         } else if (overlap == OverlapExternal) {
1118
1119                                 /* split: no split required.
1120                                    cut: remove the region.
1121                                 */
1122
1123                                 /*
1124                                        start                                      end
1125                                     ---------------*************************------------
1126                                        P2          P1 P3                   P4
1127
1128                                     SPLIT:
1129                                     ---------------*************************------------
1130                                     CUT:
1131                                     ----------------------------------------------------
1132
1133                                 */
1134
1135                                 if (cutting) {
1136                                         remove_region_internal (current);
1137                                 }
1138
1139                                 new_regions.push_back (current);
1140                         }
1141                 }
1142
1143                 in_partition = false;
1144         }
1145
1146         for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
1147                 check_dependents (*i, false);
1148         }
1149 }
1150
1151 boost::shared_ptr<Playlist>
1152 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
1153 {
1154         boost::shared_ptr<Playlist> ret;
1155         boost::shared_ptr<Playlist> pl;
1156         framepos_t start;
1157
1158         if (ranges.empty()) {
1159                 return boost::shared_ptr<Playlist>();
1160         }
1161
1162         start = ranges.front().start;
1163
1164         for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
1165
1166                 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
1167
1168                 if (i == ranges.begin()) {
1169                         ret = pl;
1170                 } else {
1171
1172                         /* paste the next section into the nascent playlist,
1173                            offset to reflect the start of the first range we
1174                            chopped.
1175                         */
1176
1177                         ret->paste (pl, (*i).start - start, 1.0f);
1178                 }
1179         }
1180
1181         return ret;
1182 }
1183
1184 boost::shared_ptr<Playlist>
1185 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
1186 {
1187         boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
1188         return cut_copy (pmf, ranges, result_is_hidden);
1189 }
1190
1191 boost::shared_ptr<Playlist>
1192 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
1193 {
1194         boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
1195         return cut_copy (pmf, ranges, result_is_hidden);
1196 }
1197
1198 boost::shared_ptr<Playlist>
1199 Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1200 {
1201         boost::shared_ptr<Playlist> the_copy;
1202         RegionList thawlist;
1203         char buf[32];
1204
1205         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1206         string new_name = _name;
1207         new_name += '.';
1208         new_name += buf;
1209
1210         if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
1211                 return boost::shared_ptr<Playlist>();
1212         }
1213
1214         partition_internal (start, start+cnt-1, true, thawlist);
1215
1216         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
1217                 (*i)->resume_property_changes();
1218         }
1219
1220         return the_copy;
1221 }
1222
1223 boost::shared_ptr<Playlist>
1224 Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
1225 {
1226         char buf[32];
1227
1228         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
1229         string new_name = _name;
1230         new_name += '.';
1231         new_name += buf;
1232
1233         cnt = min (_get_extent().second - start, cnt);
1234         return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
1235 }
1236
1237 int
1238 Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
1239 {
1240         times = fabs (times);
1241
1242         {
1243                 RegionLock rl1 (this);
1244                 RegionLock rl2 (other.get());
1245
1246                 framecnt_t const old_length = _get_extent().second;
1247
1248                 int itimes = (int) floor (times);
1249                 framepos_t pos = position;
1250                 framecnt_t const shift = other->_get_extent().second;
1251                 layer_t top_layer = regions.size();
1252
1253                 while (itimes--) {
1254                         for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
1255                                 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
1256
1257                                 /* put these new regions on top of all existing ones, but preserve
1258                                    the ordering they had in the original playlist.
1259                                 */
1260
1261                                 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
1262                                 cerr << "DEBUG: add new region at " << pos << endl;
1263                                 add_region_internal (copy_of_region, (*i)->position() + pos);
1264                         }
1265                         pos += shift;
1266                 }
1267
1268
1269                 /* XXX shall we handle fractional cases at some point? */
1270
1271                 if (old_length != _get_extent().second) {
1272                         notify_length_changed ();
1273                 }
1274
1275
1276         }
1277
1278         return 0;
1279 }
1280
1281
1282 void
1283 Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
1284 {
1285         times = fabs (times);
1286
1287         RegionLock rl (this);
1288         int itimes = (int) floor (times);
1289         framepos_t pos = position + 1;
1290
1291         while (itimes--) {
1292                 boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
1293                 add_region_internal (copy, pos);
1294                 pos += region->length();
1295         }
1296
1297         if (floor (times) != times) {
1298                 framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
1299                 string name;
1300                 RegionFactory::region_name (name, region->name(), false);
1301                 
1302                 {
1303                         PropertyList plist;
1304                         
1305                         plist.add (Properties::start, region->start());
1306                         plist.add (Properties::length, length);
1307                         plist.add (Properties::name, name);
1308                         
1309                         boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
1310                         add_region_internal (sub, pos);
1311                 }
1312         }
1313 }
1314
1315 void
1316 Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
1317 {
1318         RegionLock rlock (this);
1319         RegionList copy (regions.rlist());
1320         RegionList fixup;
1321
1322         for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1323
1324                 if ((*r)->last_frame() < at) {
1325                         /* too early */
1326                         continue;
1327                 }
1328
1329                 if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
1330                         /* intersected region */
1331                         if (!move_intersected) {
1332                                 continue;
1333                         }
1334                 }
1335
1336                 /* do not move regions glued to music time - that
1337                    has to be done separately.
1338                 */
1339
1340                 if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
1341                         fixup.push_back (*r);
1342                         continue;
1343                 }
1344
1345                 (*r)->set_position ((*r)->position() + distance, this);
1346         }
1347
1348         for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
1349                 (*r)->recompute_position_from_lock_style ();
1350         }
1351 }
1352
1353 void
1354 Playlist::split (framepos_t at)
1355 {
1356         RegionLock rlock (this);
1357         RegionList copy (regions.rlist());
1358
1359         /* use a copy since this operation can modify the region list
1360          */
1361
1362         for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
1363                 _split_region (*r, at);
1364         }
1365 }
1366
1367 void
1368 Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1369 {
1370         RegionLock rl (this);
1371         _split_region (region, playlist_position);
1372 }
1373
1374 void
1375 Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
1376 {
1377         if (!region->covers (playlist_position)) {
1378                 return;
1379         }
1380
1381         if (region->position() == playlist_position ||
1382             region->last_frame() == playlist_position) {
1383                 return;
1384         }
1385
1386         boost::shared_ptr<Region> left;
1387         boost::shared_ptr<Region> right;
1388         frameoffset_t before;
1389         frameoffset_t after;
1390         string before_name;
1391         string after_name;
1392
1393         /* split doesn't change anything about length, so don't try to splice */
1394
1395         bool old_sp = _splicing;
1396         _splicing = true;
1397
1398         before = playlist_position - region->position();
1399         after = region->length() - before;
1400
1401         RegionFactory::region_name (before_name, region->name(), false);
1402
1403         {
1404                 PropertyList plist;
1405
1406                 plist.add (Properties::position, region->position ());
1407                 plist.add (Properties::length, before);
1408                 plist.add (Properties::name, before_name);
1409                 plist.add (Properties::left_of_split, true);
1410
1411                 /* note: we must use the version of ::create with an offset here,
1412                    since it supplies that offset to the Region constructor, which
1413                    is necessary to get audio region gain envelopes right.
1414                 */
1415                 left = RegionFactory::create (region, 0, plist);
1416         }
1417
1418         RegionFactory::region_name (after_name, region->name(), false);
1419
1420         {
1421                 PropertyList plist;
1422
1423                 plist.add (Properties::position, region->position() + before);
1424                 plist.add (Properties::length, after);
1425                 plist.add (Properties::name, after_name);
1426                 plist.add (Properties::right_of_split, true);
1427
1428                 /* same note as above */
1429                 right = RegionFactory::create (region, before, plist);
1430         }
1431
1432         add_region_internal (left, region->position());
1433         add_region_internal (right, region->position() + before);
1434
1435         uint64_t orig_layer_op = region->last_layer_op();
1436         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1437                 if ((*i)->last_layer_op() > orig_layer_op) {
1438                         (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1439                 }
1440         }
1441
1442         left->set_last_layer_op ( orig_layer_op );
1443         right->set_last_layer_op ( orig_layer_op + 1);
1444
1445         layer_op_counter++;
1446
1447         finalize_split_region (region, left, right);
1448
1449         remove_region_internal (region);
1450
1451         _splicing = old_sp;
1452 }
1453
1454 void
1455 Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1456 {
1457         if (_splicing || in_set_state) {
1458                 /* don't respond to splicing moves or state setting */
1459                 return;
1460         }
1461
1462         if (_edit_mode == Splice) {
1463                 splice_locked (at, distance, exclude);
1464         }
1465 }
1466
1467 void
1468 Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1469 {
1470         if (_splicing || in_set_state) {
1471                 /* don't respond to splicing moves or state setting */
1472                 return;
1473         }
1474
1475         if (_edit_mode == Splice) {
1476                 splice_unlocked (at, distance, exclude);
1477         }
1478 }
1479
1480 void
1481 Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1482 {
1483         {
1484                 RegionLock rl (this);
1485                 core_splice (at, distance, exclude);
1486         }
1487 }
1488
1489 void
1490 Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1491 {
1492         core_splice (at, distance, exclude);
1493 }
1494
1495 void
1496 Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude)
1497 {
1498         _splicing = true;
1499
1500         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1501
1502                 if (exclude && (*i) == exclude) {
1503                         continue;
1504                 }
1505
1506                 if ((*i)->position() >= at) {
1507                         framepos_t new_pos = (*i)->position() + distance;
1508                         if (new_pos < 0) {
1509                                 new_pos = 0;
1510                         } else if (new_pos >= max_framepos - (*i)->length()) {
1511                                 new_pos = max_framepos - (*i)->length();
1512                         }
1513
1514                         (*i)->set_position (new_pos, this);
1515                 }
1516         }
1517
1518         _splicing = false;
1519
1520         notify_length_changed ();
1521 }
1522
1523 void
1524 Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1525 {
1526         if (in_set_state || _splicing || _nudging || _shuffling) {
1527                 return;
1528         }
1529
1530         if (what_changed.contains (Properties::position)) {
1531
1532                 /* remove it from the list then add it back in
1533                    the right place again.
1534                 */
1535
1536                 RegionSortByPosition cmp;
1537
1538                 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1539
1540                 if (i == regions.end()) {
1541                         /* the region bounds are being modified but its not currently
1542                            in the region list. we will use its bounds correctly when/if
1543                            it is added
1544                         */
1545                         return;
1546                 }
1547
1548                 regions.erase (i);
1549                 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1550         }
1551
1552         if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) {
1553
1554                 frameoffset_t delta = 0;
1555
1556                 if (what_changed.contains (Properties::position)) {
1557                         delta = region->position() - region->last_position();
1558                 }
1559
1560                 if (what_changed.contains (Properties::length)) {
1561                         delta += region->length() - region->last_length();
1562                 }
1563
1564                 if (delta) {
1565                         possibly_splice (region->last_position() + region->last_length(), delta, region);
1566                 }
1567
1568                 if (holding_state ()) {
1569                         pending_bounds.push_back (region);
1570                 } else {
1571                         if (_session.config.get_layer_model() == MoveAddHigher) {
1572                                 /* it moved or changed length, so change the timestamp */
1573                                 timestamp_layer_op (region);
1574                         }
1575
1576                         notify_length_changed ();
1577                         relayer ();
1578                         check_dependents (region, false);
1579                 }
1580         }
1581 }
1582
1583 void
1584 Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr<Region> weak_region)
1585 {
1586         boost::shared_ptr<Region> region (weak_region.lock());
1587
1588         if (!region) {
1589                 return;
1590         }
1591
1592         /* this makes a virtual call to the right kind of playlist ... */
1593
1594         region_changed (what_changed, region);
1595 }
1596
1597 bool
1598 Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
1599 {
1600         PropertyChange our_interests;
1601         PropertyChange bounds;
1602         PropertyChange pos_and_length;
1603         bool save = false;
1604
1605         if (in_set_state || in_flush) {
1606                 return false;
1607         }
1608
1609         our_interests.add (Properties::muted);
1610         our_interests.add (Properties::layer);
1611         our_interests.add (Properties::opaque);
1612
1613         bounds.add (Properties::start);
1614         bounds.add (Properties::position);
1615         bounds.add (Properties::length);
1616
1617         pos_and_length.add (Properties::position);
1618         pos_and_length.add (Properties::length);
1619
1620         if (what_changed.contains (bounds)) {
1621                 region_bounds_changed (what_changed, region);
1622                 save = !(_splicing || _nudging);
1623         }
1624
1625         if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
1626                 check_dependents (region, false);
1627         }
1628
1629         if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
1630                 notify_region_moved (region);
1631         }
1632
1633
1634         /* don't notify about layer changes, since we are the only object that can initiate
1635            them, and we notify in ::relayer()
1636         */
1637
1638         if (what_changed.contains (our_interests)) {
1639                 save = true;
1640         }
1641
1642         return save;
1643 }
1644
1645 void
1646 Playlist::drop_regions ()
1647 {
1648         RegionLock rl (this);
1649         regions.clear ();
1650         all_regions.clear ();
1651 }
1652
1653 void
1654 Playlist::clear (bool with_signals)
1655 {
1656         {
1657                 RegionLock rl (this);
1658
1659                 region_state_changed_connections.drop_connections ();
1660
1661                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1662                         pending_removes.insert (*i);
1663                 }
1664
1665                 regions.clear ();
1666
1667                 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1668                         remove_dependents (*s);
1669                 }
1670         }
1671
1672         if (with_signals) {
1673
1674                 for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
1675                         RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
1676                 }
1677
1678                 pending_removes.clear ();
1679                 pending_length = false;
1680                 LengthChanged ();
1681                 pending_contents_change = false;
1682                 ContentsChanged ();
1683         }
1684
1685 }
1686
1687 /***********************************************************************
1688  FINDING THINGS
1689  **********************************************************************/
1690
1691 Playlist::RegionList *
1692 Playlist::regions_at (framepos_t frame)
1693
1694 {
1695         RegionLock rlock (this);
1696         return find_regions_at (frame);
1697 }
1698
1699 uint32_t
1700 Playlist::count_regions_at (framepos_t frame)
1701 {
1702         RegionLock rlock (this);
1703         uint32_t cnt = 0;
1704
1705         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1706                 if ((*i)->covers (frame)) {
1707                         cnt++;
1708                 }
1709         }
1710
1711         return cnt;
1712 }
1713
1714 boost::shared_ptr<Region>
1715 Playlist::top_region_at (framepos_t frame)
1716
1717 {
1718         RegionLock rlock (this);
1719         RegionList *rlist = find_regions_at (frame);
1720         boost::shared_ptr<Region> region;
1721
1722         if (rlist->size()) {
1723                 RegionSortByLayer cmp;
1724                 rlist->sort (cmp);
1725                 region = rlist->back();
1726         }
1727
1728         delete rlist;
1729         return region;
1730 }
1731
1732 boost::shared_ptr<Region>
1733 Playlist::top_unmuted_region_at (framepos_t frame)
1734
1735 {
1736         RegionLock rlock (this);
1737         RegionList *rlist = find_regions_at (frame);
1738
1739         for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) {
1740
1741                 RegionList::iterator tmp = i;
1742                 ++tmp;
1743
1744                 if ((*i)->muted()) {
1745                         rlist->erase (i);
1746                 }
1747
1748                 i = tmp;
1749         }
1750
1751         boost::shared_ptr<Region> region;
1752
1753         if (rlist->size()) {
1754                 RegionSortByLayer cmp;
1755                 rlist->sort (cmp);
1756                 region = rlist->back();
1757         }
1758
1759         delete rlist;
1760         return region;
1761 }
1762
1763 Playlist::RegionList*
1764 Playlist::regions_to_read (framepos_t start, framepos_t end)
1765 {
1766         /* Caller must hold lock */
1767
1768         RegionList covering;
1769         set<framepos_t> to_check;
1770         set<boost::shared_ptr<Region> > unique;
1771
1772         to_check.insert (start);
1773         to_check.insert (end);
1774
1775         DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
1776
1777         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1778
1779                 /* find all/any regions that span start+end */
1780
1781                 switch ((*i)->coverage (start, end)) {
1782                 case OverlapNone:
1783                         break;
1784
1785                 case OverlapInternal:
1786                         covering.push_back (*i);
1787                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
1788                         break;
1789
1790                 case OverlapStart:
1791                         to_check.insert ((*i)->position());
1792                         if ((*i)->position() != 0) {
1793                                 to_check.insert ((*i)->position()-1);
1794                         }
1795                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1796                         covering.push_back (*i);
1797                         break;
1798
1799                 case OverlapEnd:
1800                         to_check.insert ((*i)->last_frame());
1801                         to_check.insert ((*i)->last_frame()+1);
1802                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
1803                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1804                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1805                         covering.push_back (*i);
1806                         break;
1807
1808                 case OverlapExternal:
1809                         covering.push_back (*i);
1810                         to_check.insert ((*i)->position());
1811                         if ((*i)->position() != 0) {
1812                                 to_check.insert ((*i)->position()-1);
1813                         }
1814                         to_check.insert ((*i)->last_frame());
1815                         to_check.insert ((*i)->last_frame()+1);
1816                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
1817                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
1818                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
1819                         break;
1820                 }
1821
1822                 /* don't go too far */
1823
1824                 if ((*i)->position() > end) {
1825                         break;
1826                 }
1827         }
1828
1829         RegionList* rlist = new RegionList;
1830
1831         /* find all the regions that cover each position .... */
1832
1833         if (covering.size() == 1) {
1834
1835                 rlist->push_back (covering.front());
1836                 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
1837
1838         } else {
1839
1840                 RegionList here;
1841                 for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1842
1843                         here.clear ();
1844
1845                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
1846
1847                         for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1848
1849                                 if ((*x)->covers (*t)) {
1850                                         here.push_back (*x);
1851                                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
1852                                                                                            (*x)->name(),
1853                                                                                            (*t)));
1854                                 } else {
1855                                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
1856                                                                                            (*x)->name(),
1857                                                                                            (*t)));
1858                                 }
1859                                         
1860                         }
1861
1862                         RegionSortByLayer cmp;
1863                         here.sort (cmp);
1864
1865                         /* ... and get the top/transparent regions at "here" */
1866
1867                         for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1868
1869                                 unique.insert (*c);
1870
1871                                 if ((*c)->opaque()) {
1872
1873                                         /* the other regions at this position are hidden by this one */
1874                                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
1875                                                                                            (*c)->name()));
1876                                         break;
1877                                 }
1878                         }
1879                 }
1880
1881                 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1882                         rlist->push_back (*s);
1883                 }
1884
1885                 if (rlist->size() > 1) {
1886                         /* now sort by time order */
1887
1888                         RegionSortByPosition cmp;
1889                         rlist->sort (cmp);
1890                 }
1891         }
1892
1893         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
1894
1895         return rlist;
1896 }
1897
1898 Playlist::RegionList *
1899 Playlist::find_regions_at (framepos_t frame)
1900 {
1901         /* Caller must hold lock */
1902
1903         RegionList *rlist = new RegionList;
1904
1905         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1906                 if ((*i)->covers (frame)) {
1907                         rlist->push_back (*i);
1908                 }
1909         }
1910
1911         return rlist;
1912 }
1913
1914 Playlist::RegionList *
1915 Playlist::regions_touched (framepos_t start, framepos_t end)
1916 {
1917         RegionLock rlock (this);
1918         RegionList *rlist = new RegionList;
1919
1920         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1921                 if ((*i)->coverage (start, end) != OverlapNone) {
1922                         rlist->push_back (*i);
1923                 }
1924         }
1925
1926         return rlist;
1927 }
1928
1929 framepos_t
1930 Playlist::find_next_transient (framepos_t from, int dir)
1931 {
1932         RegionLock rlock (this);
1933         AnalysisFeatureList points;
1934         AnalysisFeatureList these_points;
1935
1936         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1937                 if (dir > 0) {
1938                         if ((*i)->last_frame() < from) {
1939                                 continue;
1940                         }
1941                 } else {
1942                         if ((*i)->first_frame() > from) {
1943                                 continue;
1944                         }
1945                 }
1946
1947                 (*i)->get_transients (these_points);
1948
1949                 /* add first frame, just, err, because */
1950
1951                 these_points.push_back ((*i)->first_frame());
1952
1953                 points.insert (points.end(), these_points.begin(), these_points.end());
1954                 these_points.clear ();
1955         }
1956
1957         if (points.empty()) {
1958                 return -1;
1959         }
1960
1961         TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1962         bool reached = false;
1963
1964         if (dir > 0) {
1965                 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1966                         if ((*x) >= from) {
1967                                 reached = true;
1968                         }
1969
1970                         if (reached && (*x) > from) {
1971                                 return *x;
1972                         }
1973                 }
1974         } else {
1975                 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1976                         if ((*x) <= from) {
1977                                 reached = true;
1978                         }
1979
1980                         if (reached && (*x) < from) {
1981                                 return *x;
1982                         }
1983                 }
1984         }
1985
1986         return -1;
1987 }
1988
1989 boost::shared_ptr<Region>
1990 Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
1991 {
1992         RegionLock rlock (this);
1993         boost::shared_ptr<Region> ret;
1994         framepos_t closest = max_framepos;
1995
1996         bool end_iter = false;
1997
1998         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1999
2000                 if(end_iter) break;
2001
2002                 frameoffset_t distance;
2003                 boost::shared_ptr<Region> r = (*i);
2004                 framepos_t pos = 0;
2005
2006                 switch (point) {
2007                 case Start:
2008                         pos = r->first_frame ();
2009                         break;
2010                 case End:
2011                         pos = r->last_frame ();
2012                         break;
2013                 case SyncPoint:
2014                         pos = r->sync_position ();
2015                         break;
2016                 }
2017
2018                 switch (dir) {
2019                 case 1: /* forwards */
2020
2021                         if (pos > frame) {
2022                                 if ((distance = pos - frame) < closest) {
2023                                         closest = distance;
2024                                         ret = r;
2025                                         end_iter = true;
2026                                 }
2027                         }
2028
2029                         break;
2030
2031                 default: /* backwards */
2032
2033                         if (pos < frame) {
2034                                 if ((distance = frame - pos) < closest) {
2035                                         closest = distance;
2036                                         ret = r;
2037                                 }
2038                         }
2039                         else {
2040                                 end_iter = true;
2041                         }
2042
2043                         break;
2044                 }
2045         }
2046
2047         return ret;
2048 }
2049
2050 framepos_t
2051 Playlist::find_next_region_boundary (framepos_t frame, int dir)
2052 {
2053         RegionLock rlock (this);
2054
2055         framepos_t closest = max_framepos;
2056         framepos_t ret = -1;
2057
2058         if (dir > 0) {
2059
2060                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2061
2062                         boost::shared_ptr<Region> r = (*i);
2063                         frameoffset_t distance;
2064
2065                         if (r->first_frame() > frame) {
2066
2067                                 distance = r->first_frame() - frame;
2068
2069                                 if (distance < closest) {
2070                                         ret = r->first_frame();
2071                                         closest = distance;
2072                                 }
2073                         }
2074
2075                         if (r->last_frame () > frame) {
2076
2077                                 distance = r->last_frame () - frame;
2078
2079                                 if (distance < closest) {
2080                                         ret = r->last_frame ();
2081                                         closest = distance;
2082                                 }
2083                         }
2084                 }
2085
2086         } else {
2087
2088                 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
2089
2090                         boost::shared_ptr<Region> r = (*i);
2091                         frameoffset_t distance;
2092
2093                         if (r->last_frame() < frame) {
2094
2095                                 distance = frame - r->last_frame();
2096
2097                                 if (distance < closest) {
2098                                         ret = r->last_frame();
2099                                         closest = distance;
2100                                 }
2101                         }
2102
2103                         if (r->first_frame() < frame) {
2104
2105                                 distance = frame - r->first_frame();
2106
2107                                 if (distance < closest) {
2108                                         ret = r->first_frame();
2109                                         closest = distance;
2110                                 }
2111                         }
2112                 }
2113         }
2114
2115         return ret;
2116 }
2117
2118
2119 /***********************************************************************/
2120
2121
2122
2123
2124 void
2125 Playlist::mark_session_dirty ()
2126 {
2127         if (!in_set_state && !holding_state ()) {
2128                 _session.set_dirty();
2129         }
2130 }
2131
2132 void
2133 Playlist::rdiff (vector<Command*>& cmds) const
2134 {
2135         RegionLock rlock (const_cast<Playlist *> (this));
2136         Stateful::rdiff (cmds);
2137 }
2138
2139 void
2140 Playlist::clear_owned_changes ()
2141 {
2142         RegionLock rlock (this);
2143         Stateful::clear_owned_changes ();
2144 }
2145
2146 void
2147 Playlist::update (const RegionListProperty::ChangeRecord& change)
2148 {
2149         DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n", 
2150                                                         name(), change.added.size(), change.removed.size()));
2151         
2152         freeze ();
2153         /* add the added regions */
2154         for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
2155                 add_region ((*i), (*i)->position());
2156         }
2157         /* remove the removed regions */
2158         for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
2159                 remove_region (*i);
2160         }
2161
2162         thaw ();
2163 }
2164
2165 int
2166 Playlist::set_state (const XMLNode& node, int version)
2167 {
2168         XMLNode *child;
2169         XMLNodeList nlist;
2170         XMLNodeConstIterator niter;
2171         XMLPropertyList plist;
2172         XMLPropertyConstIterator piter;
2173         XMLProperty *prop;
2174         boost::shared_ptr<Region> region;
2175         string region_name;
2176
2177         in_set_state++;
2178
2179         if (node.name() != "Playlist") {
2180                 in_set_state--;
2181                 return -1;
2182         }
2183
2184         freeze ();
2185
2186         plist = node.properties();
2187
2188         for (piter = plist.begin(); piter != plist.end(); ++piter) {
2189
2190                 prop = *piter;
2191
2192                 if (prop->name() == X_("name")) {
2193                         _name = prop->value();
2194                         _set_sort_id ();
2195                 } else if (prop->name() == X_("id")) {
2196                         _id = prop->value();
2197                 } else if (prop->name() == X_("orig_diskstream_id")) {
2198                         _orig_diskstream_id = prop->value ();
2199                 } else if (prop->name() == X_("frozen")) {
2200                         _frozen = string_is_affirmative (prop->value());
2201                 }
2202         }
2203
2204         clear (true);
2205
2206         nlist = node.children();
2207
2208         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2209
2210                 child = *niter;
2211
2212                 if (child->name() == "Region") {
2213
2214                         if ((prop = child->property ("id")) == 0) {
2215                                 error << _("region state node has no ID, ignored") << endmsg;
2216                                 continue;
2217                         }
2218                         
2219                         ID id = prop->value ();
2220
2221                         if ((region = region_by_id (id))) {
2222
2223                                 region->suspend_property_changes ();
2224
2225                                 if (region->set_state (*child, version)) {
2226                                         region->resume_property_changes ();
2227                                         continue;
2228                                 }
2229                                 
2230                         } else if ((region = RegionFactory::create (_session, *child, true)) != 0) {
2231                                 region->suspend_property_changes ();
2232                         } else {
2233                                 error << _("Playlist: cannot create region from XML") << endmsg;
2234                                 continue;
2235                         }
2236
2237
2238                         add_region (region, region->position(), 1.0);
2239
2240                         // So that layer_op ordering doesn't get screwed up
2241                         region->set_last_layer_op( region->layer());
2242                         region->resume_property_changes ();
2243                 }
2244         }
2245
2246         /* update dependents, which was not done during add_region_internal
2247            due to in_set_state being true
2248         */
2249
2250         for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
2251                 check_dependents (*r, false);
2252         }
2253
2254         thaw ();
2255         notify_contents_changed ();
2256
2257         in_set_state--;
2258         first_set_state = false;
2259         return 0;
2260 }
2261
2262 XMLNode&
2263 Playlist::get_state()
2264 {
2265         return state (true);
2266 }
2267
2268 XMLNode&
2269 Playlist::get_template()
2270 {
2271         return state (false);
2272 }
2273
2274 /** @param full_state true to include regions in the returned state, otherwise false.
2275  */
2276 XMLNode&
2277 Playlist::state (bool full_state)
2278 {
2279         XMLNode *node = new XMLNode (X_("Playlist"));
2280         char buf[64] = "";
2281
2282         node->add_property (X_("id"), id().to_s());
2283         node->add_property (X_("name"), _name);
2284         node->add_property (X_("type"), _type.to_string());
2285
2286         _orig_diskstream_id.print (buf, sizeof (buf));
2287         node->add_property (X_("orig_diskstream_id"), buf);
2288         node->add_property (X_("frozen"), _frozen ? "yes" : "no");
2289
2290         if (full_state) {
2291                 RegionLock rlock (this, false);
2292
2293                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2294                         node->add_child_nocopy ((*i)->get_state());
2295                 }
2296         }
2297
2298         if (_extra_xml) {
2299                 node->add_child_copy (*_extra_xml);
2300         }
2301
2302         return *node;
2303 }
2304
2305 bool
2306 Playlist::empty() const
2307 {
2308         RegionLock rlock (const_cast<Playlist *>(this), false);
2309         return regions.empty();
2310 }
2311
2312 uint32_t
2313 Playlist::n_regions() const
2314 {
2315         RegionLock rlock (const_cast<Playlist *>(this), false);
2316         return regions.size();
2317 }
2318
2319 pair<framepos_t, framepos_t>
2320 Playlist::get_extent () const
2321 {
2322         RegionLock rlock (const_cast<Playlist *>(this), false);
2323         return _get_extent ();
2324 }
2325
2326 pair<framepos_t, framepos_t>
2327 Playlist::_get_extent () const
2328 {
2329         pair<framepos_t, framepos_t> ext (max_framepos, 0);
2330
2331         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2332                 pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
2333                 if (e.first < ext.first) {
2334                         ext.first = e.first;
2335                 }
2336                 if (e.second > ext.second) {
2337                         ext.second = e.second;
2338                 }
2339         }
2340
2341         return ext;
2342 }
2343
2344 string
2345 Playlist::bump_name (string name, Session &session)
2346 {
2347         string newname = name;
2348
2349         do {
2350                 newname = bump_name_once (newname, '.');
2351         } while (session.playlists->by_name (newname)!=NULL);
2352
2353         return newname;
2354 }
2355
2356
2357 layer_t
2358 Playlist::top_layer() const
2359 {
2360         RegionLock rlock (const_cast<Playlist *> (this));
2361         layer_t top = 0;
2362
2363         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2364                 top = max (top, (*i)->layer());
2365         }
2366         return top;
2367 }
2368
2369 void
2370 Playlist::set_edit_mode (EditMode mode)
2371 {
2372         _edit_mode = mode;
2373 }
2374
2375 /********************
2376  * Region Layering
2377  ********************/
2378
2379 void
2380 Playlist::relayer ()
2381 {
2382         /* never compute layers when changing state for undo/redo or setting from XML */
2383
2384         if (in_update || in_set_state) {
2385                 return;
2386         }
2387
2388         bool changed = false;
2389
2390         /* Build up a new list of regions on each layer, stored in a set of lists
2391            each of which represent some period of time on some layer.  The idea
2392            is to avoid having to search the entire region list to establish whether
2393            each region overlaps another */
2394
2395         /* how many pieces to divide this playlist's time up into */
2396         int const divisions = 512;
2397
2398         /* find the start and end positions of the regions on this playlist */
2399         framepos_t start = INT64_MAX;
2400         framepos_t end = 0;
2401         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2402                 start = min (start, (*i)->position());
2403                 end = max (end, (*i)->position() + (*i)->length());
2404         }
2405
2406         /* hence the size of each time division */
2407         double const division_size = (end - start) / double (divisions);
2408
2409         vector<vector<RegionList> > layers;
2410         layers.push_back (vector<RegionList> (divisions));
2411
2412         /* we want to go through regions from desired lowest to desired highest layer,
2413            which depends on the layer model
2414         */
2415
2416         RegionList copy = regions.rlist();
2417
2418         /* sort according to the model and the layering mode that we're in */
2419
2420         if (_explicit_relayering) {
2421
2422                 copy.sort (RegionSortByLayerWithPending ());
2423
2424         } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2425
2426                 copy.sort (RegionSortByLastLayerOp ());
2427
2428         }
2429
2430
2431         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2432
2433                 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2434                 (*i)->set_pending_explicit_relayer (false);
2435
2436                 /* find the time divisions that this region covers; if there are no regions on the list,
2437                    division_size will equal 0 and in this case we'll just say that
2438                    start_division = end_division = 0.
2439                 */
2440                 int start_division = 0;
2441                 int end_division = 0;
2442
2443                 if (division_size > 0) {
2444                         start_division = floor ( ((*i)->position() - start) / division_size);
2445                         end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2446                         if (end_division == divisions) {
2447                                 end_division--;
2448                         }
2449                 }
2450
2451                 assert (divisions == 0 || end_division < divisions);
2452
2453                 /* find the lowest layer that this region can go on */
2454                 size_t j = layers.size();
2455                 while (j > 0) {
2456                         /* try layer j - 1; it can go on if it overlaps no other region
2457                            that is already on that layer
2458                         */
2459
2460                         bool overlap = false;
2461                         for (int k = start_division; k <= end_division; ++k) {
2462                                 RegionList::iterator l = layers[j-1][k].begin ();
2463                                 while (l != layers[j-1][k].end()) {
2464                                         if ((*l)->overlap_equivalent (*i)) {
2465                                                 overlap = true;
2466                                                 break;
2467                                         }
2468                                         l++;
2469                                 }
2470
2471                                 if (overlap) {
2472                                         break;
2473                                 }
2474                         }
2475
2476                         if (overlap) {
2477                                 /* overlap, so we must use layer j */
2478                                 break;
2479                         }
2480
2481                         --j;
2482                 }
2483
2484                 if (j == layers.size()) {
2485                         /* we need a new layer for this region */
2486                         layers.push_back (vector<RegionList> (divisions));
2487                 }
2488
2489                 /* put a reference to this region in each of the divisions that it exists in */
2490                 for (int k = start_division; k <= end_division; ++k) {
2491                         layers[j][k].push_back (*i);
2492                 }
2493                 
2494                 if ((*i)->layer() != j) {
2495                         changed = true;
2496                 }
2497
2498                 (*i)->set_layer (j);
2499         }
2500
2501         if (changed) {
2502                 notify_layering_changed ();
2503         }
2504 }
2505
2506 /* XXX these layer functions are all deprecated */
2507
2508 void
2509 Playlist::raise_region (boost::shared_ptr<Region> region)
2510 {
2511         uint32_t top = regions.size() - 1;
2512         layer_t target = region->layer() + 1U;
2513
2514         if (target >= top) {
2515                 /* its already at the effective top */
2516                 return;
2517         }
2518
2519         move_region_to_layer (target, region, 1);
2520 }
2521
2522 void
2523 Playlist::lower_region (boost::shared_ptr<Region> region)
2524 {
2525         if (region->layer() == 0) {
2526                 /* its already at the bottom */
2527                 return;
2528         }
2529
2530         layer_t target = region->layer() - 1U;
2531
2532         move_region_to_layer (target, region, -1);
2533 }
2534
2535 void
2536 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2537 {
2538         /* does nothing useful if layering mode is later=higher */
2539         switch (_session.config.get_layer_model()) {
2540         case LaterHigher:
2541                 return;
2542         default:
2543                 break;
2544         }
2545
2546         layer_t top = regions.size() - 1;
2547
2548         if (region->layer() >= top) {
2549                 /* already on the top */
2550                 return;
2551         }
2552
2553         move_region_to_layer (top, region, 1);
2554         /* mark the region's last_layer_op as now, so that it remains on top when
2555            doing future relayers (until something else takes over)
2556          */
2557         timestamp_layer_op (region);
2558 }
2559
2560 void
2561 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2562 {
2563         /* does nothing useful if layering mode is later=higher */
2564         switch (_session.config.get_layer_model()) {
2565         case LaterHigher:
2566                 return;
2567         default:
2568                 break;
2569         }
2570
2571         if (region->layer() == 0) {
2572                 /* already on the bottom */
2573                 return;
2574         }
2575
2576         move_region_to_layer (0, region, -1);
2577         /* force region's last layer op to zero so that it stays at the bottom
2578            when doing future relayers
2579         */
2580         region->set_last_layer_op (0);
2581 }
2582
2583 int
2584 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2585 {
2586         RegionList::iterator i;
2587         typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2588         list<LayerInfo> layerinfo;
2589
2590         {
2591                 RegionLock rlock (const_cast<Playlist *> (this));
2592
2593                 for (i = regions.begin(); i != regions.end(); ++i) {
2594
2595                         if (region == *i) {
2596                                 continue;
2597                         }
2598
2599                         layer_t dest;
2600
2601                         if (dir > 0) {
2602
2603                                 /* region is moving up, move all regions on intermediate layers
2604                                    down 1
2605                                 */
2606
2607                                 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2608                                         dest = (*i)->layer() - 1;
2609                                 } else {
2610                                         /* not affected */
2611                                         continue;
2612                                 }
2613                         } else {
2614
2615                                 /* region is moving down, move all regions on intermediate layers
2616                                    up 1
2617                                 */
2618
2619                                 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2620                                         dest = (*i)->layer() + 1;
2621                                 } else {
2622                                         /* not affected */
2623                                         continue;
2624                                 }
2625                         }
2626
2627                         LayerInfo newpair;
2628
2629                         newpair.first = *i;
2630                         newpair.second = dest;
2631
2632                         layerinfo.push_back (newpair);
2633                 }
2634         }
2635
2636         freeze ();
2637
2638         /* now reset the layers without holding the region lock */
2639
2640         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2641                 x->first->set_layer (x->second);
2642         }
2643
2644         region->set_layer (target_layer);
2645
2646         /* now check all dependents, since we changed the layering */
2647
2648         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2649                 check_dependents (x->first, false);
2650         }
2651
2652         check_dependents (region, false);
2653         notify_layering_changed ();
2654
2655         thaw ();
2656
2657         return 0;
2658 }
2659
2660 void
2661 Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
2662 {
2663         RegionList::iterator i;
2664         bool moved = false;
2665
2666         _nudging = true;
2667
2668         {
2669                 RegionLock rlock (const_cast<Playlist *> (this));
2670
2671                 for (i = regions.begin(); i != regions.end(); ++i) {
2672
2673                         if ((*i)->position() >= start) {
2674
2675                                 framepos_t new_pos;
2676
2677                                 if (forwards) {
2678
2679                                         if ((*i)->last_frame() > max_framepos - distance) {
2680                                                 new_pos = max_framepos - (*i)->length();
2681                                         } else {
2682                                                 new_pos = (*i)->position() + distance;
2683                                         }
2684
2685                                 } else {
2686
2687                                         if ((*i)->position() > distance) {
2688                                                 new_pos = (*i)->position() - distance;
2689                                         } else {
2690                                                 new_pos = 0;
2691                                         }
2692                                 }
2693
2694                                 (*i)->set_position (new_pos, this);
2695                                 moved = true;
2696                         }
2697                 }
2698         }
2699
2700         if (moved) {
2701                 _nudging = false;
2702                 notify_length_changed ();
2703         }
2704
2705 }
2706
2707 boost::shared_ptr<Region>
2708 Playlist::find_region (const ID& id) const
2709 {
2710         RegionLock rlock (const_cast<Playlist*> (this));
2711
2712         /* searches all regions currently in use by the playlist */
2713
2714         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2715                 if ((*i)->id() == id) {
2716                         return *i;
2717                 }
2718         }
2719
2720         return boost::shared_ptr<Region> ();
2721 }
2722
2723 uint32_t
2724 Playlist::region_use_count (boost::shared_ptr<Region> r) const
2725 {
2726         RegionLock rlock (const_cast<Playlist*> (this));
2727         uint32_t cnt = 0;
2728
2729         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2730                 if ((*i) == r) {
2731                         cnt++;
2732                 }
2733         }
2734
2735         return cnt;
2736 }
2737
2738 boost::shared_ptr<Region>
2739 Playlist::region_by_id (const ID& id) const
2740 {
2741         /* searches all regions ever added to this playlist */
2742
2743         for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2744                 if ((*i)->id() == id) {
2745                         return *i;
2746                 }
2747         }
2748         return boost::shared_ptr<Region> ();
2749 }
2750
2751 void
2752 Playlist::dump () const
2753 {
2754         boost::shared_ptr<Region> r;
2755
2756         cerr << "Playlist \"" << _name << "\" " << endl
2757              << regions.size() << " regions "
2758              << endl;
2759
2760         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2761                 r = *i;
2762                 cerr << "  " << r->name() << " ["
2763                      << r->start() << "+" << r->length()
2764                      << "] at "
2765                      << r->position()
2766                      << " on layer "
2767                      << r->layer ()
2768                      << endl;
2769         }
2770 }
2771
2772 void
2773 Playlist::set_frozen (bool yn)
2774 {
2775         _frozen = yn;
2776 }
2777
2778 void
2779 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2780 {
2781         region->set_last_layer_op (++layer_op_counter);
2782 }
2783
2784
2785 void
2786 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2787 {
2788         bool moved = false;
2789
2790         if (region->locked()) {
2791                 return;
2792         }
2793
2794         _shuffling = true;
2795
2796         {
2797                 RegionLock rlock (const_cast<Playlist*> (this));
2798
2799
2800                 if (dir > 0) {
2801
2802                         RegionList::iterator next;
2803
2804                         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2805                                 if ((*i) == region) {
2806                                         next = i;
2807                                         ++next;
2808
2809                                         if (next != regions.end()) {
2810
2811                                                 if ((*next)->locked()) {
2812                                                         break;
2813                                                 }
2814
2815                                                 framepos_t new_pos;
2816
2817                                                 if ((*next)->position() != region->last_frame() + 1) {
2818                                                         /* they didn't used to touch, so after shuffle,
2819                                                            just have them swap positions.
2820                                                         */
2821                                                         new_pos = (*next)->position();
2822                                                 } else {
2823                                                         /* they used to touch, so after shuffle,
2824                                                            make sure they still do. put the earlier
2825                                                            region where the later one will end after
2826                                                            it is moved.
2827                                                         */
2828                                                         new_pos = region->position() + (*next)->length();
2829                                                 }
2830
2831                                                 (*next)->set_position (region->position(), this);
2832                                                 region->set_position (new_pos, this);
2833
2834                                                 /* avoid a full sort */
2835
2836                                                 regions.erase (i); // removes the region from the list */
2837                                                 next++;
2838                                                 regions.insert (next, region); // adds it back after next
2839
2840                                                 moved = true;
2841                                         }
2842                                         break;
2843                                 }
2844                         }
2845                 } else {
2846
2847                         RegionList::iterator prev = regions.end();
2848
2849                         for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {
2850                                 if ((*i) == region) {
2851
2852                                         if (prev != regions.end()) {
2853
2854                                                 if ((*prev)->locked()) {
2855                                                         break;
2856                                                 }
2857
2858                                                 framepos_t new_pos;
2859                                                 if (region->position() != (*prev)->last_frame() + 1) {
2860                                                         /* they didn't used to touch, so after shuffle,
2861                                                            just have them swap positions.
2862                                                         */
2863                                                         new_pos = region->position();
2864                                                 } else {
2865                                                         /* they used to touch, so after shuffle,
2866                                                            make sure they still do. put the earlier
2867                                                            one where the later one will end after
2868                                                         */
2869                                                         new_pos = (*prev)->position() + region->length();
2870                                                 }
2871
2872                                                 region->set_position ((*prev)->position(), this);
2873                                                 (*prev)->set_position (new_pos, this);
2874
2875                                                 /* avoid a full sort */
2876
2877                                                 regions.erase (i); // remove region
2878                                                 regions.insert (prev, region); // insert region before prev
2879
2880                                                 moved = true;
2881                                         }
2882
2883                                         break;
2884                                 }
2885                         }
2886                 }
2887         }
2888
2889         _shuffling = false;
2890
2891         if (moved) {
2892
2893                 relayer ();
2894                 check_dependents (region, false);
2895
2896                 notify_contents_changed();
2897         }
2898
2899 }
2900
2901 bool
2902 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
2903 {
2904         RegionLock rlock (const_cast<Playlist*> (this));
2905
2906         if (regions.size() > 1) {
2907                 return true;
2908         }
2909
2910         return false;
2911 }
2912
2913 void
2914 Playlist::update_after_tempo_map_change ()
2915 {
2916         RegionLock rlock (const_cast<Playlist*> (this));
2917         RegionList copy (regions.rlist());
2918
2919         freeze ();
2920
2921         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2922                 (*i)->update_position_after_tempo_map_change ();
2923         }
2924
2925         thaw ();
2926 }
2927
2928 void
2929 Playlist::foreach_region (boost::function<void(boost::shared_ptr<Region>)> s)
2930 {
2931         RegionLock rl (this, false);
2932         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2933                 s (*i);
2934         }
2935 }
2936
2937 void
2938 Playlist::set_explicit_relayering (bool e)
2939 {
2940         if (e == false && _explicit_relayering == true) {
2941
2942                 /* We are changing from explicit to implicit relayering; layering may have been changed whilst
2943                    we were in explicit mode, and we don't want that to be undone next time an implicit relayer
2944                    occurs.  Hence now we'll set up region last_layer_op values so that an implicit relayer
2945                    at this point would keep regions on the same layers.
2946
2947                    From then on in, it's just you and your towel.
2948                 */
2949
2950                 RegionLock rl (this);
2951                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2952                         (*i)->set_last_layer_op ((*i)->layer ());
2953                 }
2954         }
2955
2956         _explicit_relayering = e;
2957 }
2958
2959
2960 bool
2961 Playlist::has_region_at (framepos_t const p) const
2962 {
2963         RegionLock (const_cast<Playlist *> (this));
2964         
2965         RegionList::const_iterator i = regions.begin ();
2966         while (i != regions.end() && !(*i)->covers (p)) {
2967                 ++i;
2968         }
2969
2970         return (i != regions.end());
2971 }
2972
2973 /** Remove any region that uses a given source */
2974 void
2975 Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
2976 {
2977         RegionLock rl (this);
2978         
2979         RegionList::iterator i = regions.begin();
2980         while (i != regions.end()) {
2981                 RegionList::iterator j = i;
2982                 ++j;
2983                 
2984                 if ((*i)->uses_source (s)) {
2985                         remove_region_internal (*i);
2986                 }
2987
2988                 i = j;
2989         }
2990 }
2991
2992 /** Look from a session frame time and find the start time of the next region
2993  *  which is on the top layer of this playlist.
2994  *  @param t Time to look from.
2995  *  @return Position of next top-layered region, or max_framepos if there isn't one.
2996  */
2997 framepos_t
2998 Playlist::find_next_top_layer_position (framepos_t t) const
2999 {
3000         RegionLock rlock (const_cast<Playlist *> (this));
3001         
3002         layer_t const top = top_layer ();
3003
3004         RegionList copy = regions.rlist ();
3005         copy.sort (RegionSortByPosition ());
3006
3007         for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
3008                 if ((*i)->position() >= t && (*i)->layer() == top) {
3009                         return (*i)->position();
3010                 }
3011         }
3012
3013         return max_framepos;
3014 }