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