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