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