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