44ba67cb67167483bae5610a70136edda134e140
[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                         
1669                         if (r->first_frame() > frame) {
1670
1671                                 distance = r->first_frame() - frame;
1672                                 
1673                                 if (distance < closest) {
1674                                         ret = r->first_frame();
1675                                         closest = distance;
1676                                 }
1677                         }
1678
1679                         if (r->last_frame () > frame) {
1680                                 
1681                                 distance = r->last_frame () - frame;
1682                                 
1683                                 if (distance < closest) {
1684                                         ret = r->last_frame ();
1685                                         closest = distance;
1686                                 }
1687                         }
1688                 }
1689
1690         } else {
1691
1692                 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1693                         
1694                         boost::shared_ptr<Region> r = (*i);
1695                         nframes64_t distance;
1696
1697                         if (r->last_frame() < frame) {
1698
1699                                 distance = frame - r->last_frame();
1700                                 
1701                                 if (distance < closest) {
1702                                         ret = r->last_frame();
1703                                         closest = distance;
1704                                 }
1705                         }
1706
1707                         if (r->first_frame() < frame) {
1708                                 
1709                                 distance = frame - r->first_frame();
1710
1711                                 if (distance < closest) {
1712                                         ret = r->first_frame();
1713                                         closest = distance;
1714                                 }
1715                         }
1716                 }
1717         }
1718
1719         return ret;
1720 }
1721
1722 /***********************************************************************/
1723
1724
1725
1726 void
1727 Playlist::mark_session_dirty ()
1728 {
1729         if (!in_set_state && !holding_state ()) {
1730                 _session.set_dirty();
1731         }
1732 }
1733
1734 int
1735 Playlist::set_state (const XMLNode& node)
1736 {
1737         XMLNode *child;
1738         XMLNodeList nlist;
1739         XMLNodeConstIterator niter;
1740         XMLPropertyList plist;
1741         XMLPropertyConstIterator piter;
1742         XMLProperty *prop;
1743         boost::shared_ptr<Region> region;
1744         string region_name;
1745
1746         in_set_state++;
1747
1748         if (node.name() != "Playlist") {
1749                 in_set_state--;
1750                 return -1;
1751         }
1752
1753         freeze ();
1754
1755         plist = node.properties();
1756
1757         for (piter = plist.begin(); piter != plist.end(); ++piter) {
1758
1759                 prop = *piter;
1760                 
1761                 if (prop->name() == X_("name")) {
1762                         _name = prop->value();
1763                 } else if (prop->name() == X_("orig_diskstream_id")) {
1764                         _orig_diskstream_id = prop->value ();
1765                 } else if (prop->name() == X_("frozen")) {
1766                         _frozen = (prop->value() == X_("yes"));
1767                 }
1768         }
1769
1770         clear (false);
1771         
1772         nlist = node.children();
1773
1774         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1775
1776                 child = *niter;
1777                 
1778                 if (child->name() == "Region") {
1779
1780                         if ((prop = child->property ("id")) == 0) {
1781                                 error << _("region state node has no ID, ignored") << endmsg;
1782                                 continue;
1783                         }
1784                         
1785                         ID id = prop->value ();
1786                         
1787                         if ((region = region_by_id (id))) {
1788
1789                                 Change what_changed = Change (0);
1790
1791                                 if (region->set_live_state (*child, what_changed, true)) {
1792                                         error << _("Playlist: cannot reset region state from XML") << endmsg;
1793                                         continue;
1794                                 }
1795
1796                         } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1797                                 error << _("Playlist: cannot create region from XML") << endmsg;
1798                                 continue;
1799                         }
1800
1801                         add_region (region, region->position(), 1.0);
1802
1803                         // So that layer_op ordering doesn't get screwed up
1804                         region->set_last_layer_op( region->layer());
1805
1806                 }                       
1807         }
1808         
1809         notify_modified ();
1810
1811         thaw ();
1812
1813         /* update dependents, which was not done during add_region_internal 
1814            due to in_set_state being true 
1815         */
1816
1817         for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1818                 check_dependents (*r, false);
1819         }
1820
1821         in_set_state--;
1822         first_set_state = false;
1823         return 0;
1824 }
1825
1826 XMLNode&
1827 Playlist::get_state()
1828 {
1829         return state(true);
1830 }
1831
1832 XMLNode&
1833 Playlist::get_template()
1834 {
1835         return state(false);
1836 }
1837
1838 XMLNode&
1839 Playlist::state (bool full_state)
1840 {
1841         XMLNode *node = new XMLNode (X_("Playlist"));
1842         char buf[64];
1843         
1844         node->add_property (X_("name"), _name);
1845         node->add_property (X_("type"), _type.to_string());
1846
1847         _orig_diskstream_id.print (buf, sizeof (buf));
1848         node->add_property (X_("orig_diskstream_id"), buf);
1849         node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1850
1851         if (full_state) {
1852                 RegionLock rlock (this, false);
1853                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1854                         node->add_child_nocopy ((*i)->get_state());
1855                 }
1856         }
1857
1858         if (_extra_xml) {
1859                 node->add_child_copy (*_extra_xml);
1860         }
1861
1862         return *node;
1863 }
1864
1865 bool
1866 Playlist::empty() const
1867 {
1868         RegionLock rlock (const_cast<Playlist *>(this), false);
1869         return regions.empty();
1870 }
1871
1872 uint32_t
1873 Playlist::n_regions() const
1874 {
1875         RegionLock rlock (const_cast<Playlist *>(this), false);
1876         return regions.size();
1877 }
1878
1879 nframes_t
1880 Playlist::get_maximum_extent () const
1881 {
1882         RegionLock rlock (const_cast<Playlist *>(this), false);
1883         return _get_maximum_extent ();
1884 }
1885
1886 ARDOUR::nframes_t
1887 Playlist::_get_maximum_extent () const
1888 {
1889         RegionList::const_iterator i;
1890         nframes_t max_extent = 0;
1891         nframes_t end = 0;
1892
1893         for (i = regions.begin(); i != regions.end(); ++i) {
1894                 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1895                         max_extent = end;
1896                 }
1897         }
1898
1899         return max_extent;
1900 }
1901
1902 string 
1903 Playlist::bump_name (string name, Session &session)
1904 {
1905         string newname = name;
1906
1907         do {
1908                 newname = bump_name_once (newname);
1909         } while (session.playlist_by_name (newname)!=NULL);
1910
1911         return newname;
1912 }
1913
1914
1915 layer_t
1916 Playlist::top_layer() const
1917 {
1918         RegionLock rlock (const_cast<Playlist *> (this));       
1919         layer_t top = 0;
1920
1921         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1922                 top = max (top, (*i)->layer());
1923         }
1924         return top;
1925 }
1926
1927 void
1928 Playlist::set_edit_mode (EditMode mode)
1929 {
1930         _edit_mode = mode;
1931 }
1932
1933 /********************
1934  * Region Layering
1935  ********************/
1936
1937 void
1938 Playlist::relayer ()
1939 {
1940         /* don't send multiple Modified notifications
1941            when multiple regions are relayered.
1942         */
1943  
1944         freeze ();
1945
1946         /* build up a new list of regions on each layer */
1947
1948         std::vector<RegionList> layers;
1949
1950         /* we want to go through regions from desired lowest to desired highest layer,
1951            which depends on the layer model
1952         */
1953
1954         RegionList copy = regions;
1955
1956         /* sort according to the model */
1957
1958         if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
1959                 RegionSortByLastLayerOp cmp;
1960                 copy.sort (cmp);
1961         }
1962         
1963         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
1964
1965                 /* find the lowest layer that this region can go on */
1966                 size_t j = layers.size();
1967                 while (j > 0) {
1968                         /* try layer j - 1; it can go on if it overlaps no other region
1969                            that is already on that layer
1970                         */
1971                         RegionList::iterator k = layers[j - 1].begin();
1972                         while (k != layers[j - 1].end()) {
1973                                 if ((*k)->overlap_equivalent (*i)) {
1974                                         break;
1975                                 }
1976                                 k++;
1977                         }
1978
1979                         if (k != layers[j - 1].end()) {
1980                                 /* no overlap, so we can use this layer */
1981                                 break;
1982                         }
1983                                         
1984                         j--;
1985                 }
1986
1987                 if (j == layers.size()) {
1988                         /* we need a new layer for this region */
1989                         layers.push_back (RegionList ());
1990                 }
1991
1992                 layers[j].push_back (*i);
1993         }
1994
1995         /* first pass: set up the layer numbers in the regions */
1996         for (size_t j = 0; j < layers.size(); ++j) {
1997                 for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
1998                         (*i)->set_layer (j);
1999                 }
2000         }
2001
2002         /* sending Modified means that various kinds of layering
2003            models operate correctly at the GUI
2004            level. slightly inefficient, but only slightly.
2005
2006            We force a Modified signal here in case no layers actually
2007            changed.
2008         */
2009
2010         notify_modified ();
2011
2012         thaw ();
2013 }
2014
2015 /* XXX these layer functions are all deprecated */
2016
2017 void
2018 Playlist::raise_region (boost::shared_ptr<Region> region)
2019 {
2020         uint32_t rsz = regions.size();
2021         layer_t target = region->layer() + 1U;
2022
2023         if (target >= rsz) {
2024                 /* its already at the effective top */
2025                 return;
2026         }
2027
2028         move_region_to_layer (target, region, 1);
2029 }
2030
2031 void
2032 Playlist::lower_region (boost::shared_ptr<Region> region)
2033 {
2034         if (region->layer() == 0) {
2035                 /* its already at the bottom */
2036                 return;
2037         }
2038
2039         layer_t target = region->layer() - 1U;
2040
2041         move_region_to_layer (target, region, -1);
2042 }
2043
2044 void
2045 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2046 {
2047         /* does nothing useful if layering mode is later=higher */
2048         if ((Config->get_layer_model() == MoveAddHigher) ||
2049             (Config->get_layer_model() == AddHigher)) {
2050                 timestamp_layer_op (region);
2051                 relayer ();
2052         }
2053 }
2054
2055 void
2056 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2057 {
2058         /* does nothing useful if layering mode is later=higher */
2059         if ((Config->get_layer_model() == MoveAddHigher) ||
2060             (Config->get_layer_model() == AddHigher)) {
2061                 region->set_last_layer_op (0);
2062                 relayer ();
2063         }
2064 }
2065
2066 int
2067 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2068 {
2069         RegionList::iterator i;
2070         typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2071         list<LayerInfo> layerinfo;
2072         layer_t dest;
2073
2074         {
2075                 RegionLock rlock (const_cast<Playlist *> (this));
2076                 
2077                 for (i = regions.begin(); i != regions.end(); ++i) {
2078                         
2079                         if (region == *i) {
2080                                 continue;
2081                         }
2082
2083                         if (dir > 0) {
2084
2085                                 /* region is moving up, move all regions on intermediate layers
2086                                    down 1
2087                                 */
2088                                 
2089                                 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2090                                         dest = (*i)->layer() - 1;
2091                                 } else {
2092                                         /* not affected */
2093                                         continue;
2094                                 }
2095                         } else {
2096
2097                                 /* region is moving down, move all regions on intermediate layers
2098                                    up 1
2099                                 */
2100
2101                                 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2102                                         dest = (*i)->layer() + 1;
2103                                 } else {
2104                                         /* not affected */
2105                                         continue;
2106                                 }
2107                         }
2108
2109                         LayerInfo newpair;
2110                         
2111                         newpair.first = *i;
2112                         newpair.second = dest;
2113                         
2114                         layerinfo.push_back (newpair);
2115                 } 
2116         }
2117
2118         /* now reset the layers without holding the region lock */
2119
2120         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2121                 x->first->set_layer (x->second);
2122         }
2123
2124         region->set_layer (target_layer);
2125
2126 #if 0
2127         /* now check all dependents */
2128
2129         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2130                 check_dependents (x->first, false);
2131         }
2132         
2133         check_dependents (region, false);
2134 #endif
2135         
2136         return 0;
2137 }
2138
2139 void
2140 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2141 {
2142         RegionList::iterator i;
2143         nframes_t new_pos;
2144         bool moved = false;
2145
2146         _nudging = true;
2147
2148         {
2149                 RegionLock rlock (const_cast<Playlist *> (this));
2150                 
2151                 for (i = regions.begin(); i != regions.end(); ++i) {
2152
2153                         if ((*i)->position() >= start) {
2154
2155                                 if (forwards) {
2156
2157                                         if ((*i)->last_frame() > max_frames - distance) {
2158                                                 new_pos = max_frames - (*i)->length();
2159                                         } else {
2160                                                 new_pos = (*i)->position() + distance;
2161                                         }
2162                                         
2163                                 } else {
2164                                         
2165                                         if ((*i)->position() > distance) {
2166                                                 new_pos = (*i)->position() - distance;
2167                                         } else {
2168                                                 new_pos = 0;
2169                                         }
2170                                 }
2171
2172                                 (*i)->set_position (new_pos, this);
2173                                 moved = true;
2174                         }
2175                 }
2176         }
2177
2178         if (moved) {
2179                 _nudging = false;
2180                 notify_length_changed ();
2181         }
2182
2183 }
2184
2185 boost::shared_ptr<Region>
2186 Playlist::find_region (const ID& id) const
2187 {
2188         RegionLock rlock (const_cast<Playlist*> (this));
2189
2190         /* searches all regions currently in use by the playlist */
2191
2192         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2193                 if ((*i)->id() == id) {
2194                         return *i;
2195                 }
2196         }
2197
2198         return boost::shared_ptr<Region> ();
2199 }
2200
2201 boost::shared_ptr<Region>
2202 Playlist::region_by_id (ID id)
2203 {
2204         /* searches all regions ever added to this playlist */
2205
2206         for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2207                 if ((*i)->id() == id) {
2208                         return *i;
2209                 }
2210         }
2211         return boost::shared_ptr<Region> ();
2212 }
2213         
2214 void
2215 Playlist::dump () const
2216 {
2217         boost::shared_ptr<Region> r;
2218
2219         cerr << "Playlist \"" << _name << "\" " << endl
2220              << regions.size() << " regions "
2221              << endl;
2222
2223         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2224                 r = *i;
2225                 cerr << "  " << r->name() << " [" 
2226                      << r->start() << "+" << r->length() 
2227                      << "] at " 
2228                      << r->position()
2229                      << " on layer "
2230                      << r->layer ()
2231                      << endl;
2232         }
2233 }
2234
2235 void
2236 Playlist::set_frozen (bool yn)
2237 {
2238         _frozen = yn;
2239 }
2240
2241 void
2242 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2243 {
2244 //      struct timeval tv;
2245 //      gettimeofday (&tv, 0);
2246         region->set_last_layer_op (++layer_op_counter);
2247 }
2248
2249
2250 void
2251 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2252 {
2253         bool moved = false;
2254         nframes_t new_pos;
2255
2256         if (region->locked()) {
2257                 return;
2258         }
2259
2260         _shuffling = true;
2261
2262         {
2263                 RegionLock rlock (const_cast<Playlist*> (this));
2264                 
2265                 
2266                 if (dir > 0) {
2267                         
2268                         RegionList::iterator next;
2269
2270                         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {       
2271                                 if ((*i) == region) {
2272                                         next = i;
2273                                         ++next;
2274
2275                                         if (next != regions.end()) {
2276
2277                                                 if ((*next)->locked()) {
2278                                                         break;
2279                                                 }
2280
2281                                                 if ((*next)->position() != region->last_frame() + 1) {
2282                                                         /* they didn't used to touch, so after shuffle,
2283                                                            just have them swap positions.
2284                                                         */
2285                                                         new_pos = (*next)->position();
2286                                                 } else {
2287                                                         /* they used to touch, so after shuffle,
2288                                                            make sure they still do. put the earlier
2289                                                            region where the later one will end after
2290                                                            it is moved.
2291                                                         */
2292                                                         new_pos = region->position() + (*next)->length();
2293                                                 }
2294
2295                                                 (*next)->set_position (region->position(), this);
2296                                                 region->set_position (new_pos, this);
2297
2298                                                 /* avoid a full sort */
2299
2300                                                 regions.erase (i); // removes the region from the list */
2301                                                 next++;
2302                                                 regions.insert (next, region); // adds it back after next
2303
2304                                                 moved = true;
2305                                         }
2306                                         break;
2307                                 }
2308                         }
2309                 } else {
2310                         
2311                         RegionList::iterator prev = regions.end();
2312                         
2313                         for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {     
2314                                 if ((*i) == region) {
2315
2316                                         if (prev != regions.end()) {
2317
2318                                                 if ((*prev)->locked()) {
2319                                                         break;
2320                                                 }
2321
2322                                                 if (region->position() != (*prev)->last_frame() + 1) {
2323                                                         /* they didn't used to touch, so after shuffle,
2324                                                            just have them swap positions.
2325                                                         */
2326                                                         new_pos = region->position();
2327                                                 } else {
2328                                                         /* they used to touch, so after shuffle,
2329                                                            make sure they still do. put the earlier
2330                                                            one where the later one will end after
2331                                                         */
2332                                                         new_pos = (*prev)->position() + region->length();
2333                                                 }
2334
2335                                                 region->set_position ((*prev)->position(), this);
2336                                                 (*prev)->set_position (new_pos, this);
2337                                                 
2338                                                 /* avoid a full sort */
2339
2340                                                 regions.erase (i); // remove region
2341                                                 regions.insert (prev, region); // insert region before prev
2342
2343                                                 moved = true;
2344                                         }
2345
2346                                         break;
2347                                 }
2348                         }
2349                 }
2350         }
2351
2352         _shuffling = false;
2353
2354         if (moved) {
2355
2356                 relayer ();
2357                 check_dependents (region, false);
2358                 
2359                 notify_modified();
2360         }
2361
2362 }
2363
2364 bool
2365 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>) 
2366 {
2367         RegionLock rlock (const_cast<Playlist*> (this));
2368         
2369         if (regions.size() > 1) {
2370                 return true;
2371         }
2372
2373         return false;
2374 }
2375
2376 void
2377 Playlist::update_after_tempo_map_change ()
2378 {
2379         RegionLock rlock (const_cast<Playlist*> (this));
2380         RegionList copy (regions);
2381
2382         freeze ();
2383         
2384         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {     
2385                 (*i)->update_position_after_tempo_map_change ();
2386         }
2387
2388         thaw ();
2389 }