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