Merged with trunk R1283.
[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     $Id$
19 */
20
21 #include <set>
22 #include <fstream>
23 #include <algorithm>
24 #include <unistd.h>
25 #include <cerrno>
26 #include <string>
27 #include <climits>
28
29 #include <sigc++/bind.h>
30
31 #include <pbd/failed_constructor.h>
32 #include <pbd/stl_delete.h>
33 #include <pbd/xml++.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
41 #include "i18n.h"
42
43 using namespace std;
44 using namespace ARDOUR;
45 using namespace PBD;
46
47 struct ShowMeTheList {
48     ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
49     ~ShowMeTheList () { 
50             cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl; 
51     };
52     boost::shared_ptr<Playlist> playlist;
53     string name;
54 };
55
56 struct RegionSortByLayer {
57     bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
58             return a->layer() < b->layer();
59     }
60 };
61
62 struct RegionSortByPosition {
63     bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
64             return a->position() < b->position();
65     }
66 };
67
68 struct RegionSortByLastLayerOp {
69     bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
70             return a->last_layer_op() < b->last_layer_op();
71     }
72 };
73
74 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
75         : _session (sess)
76         , _type(type)
77 {
78         init (hide);
79         _name = nom;
80         
81 }
82
83 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
84         : _session (sess)
85         , _type(type)
86 {
87         const XMLProperty* prop = node.property("type");
88         assert(!prop || DataType(prop->value()) == _type);
89
90         init (hide);
91         _name = "unnamed"; /* reset by set_state */
92
93         /* set state called by derived class */
94 }
95
96 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
97         : _name (namestr), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
98 {
99         init (hide);
100
101         RegionList tmp;
102         other->copy_regions (tmp);
103         
104         in_set_state++;
105
106         for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
107                 add_region_internal( (*x), (*x)->position());
108         }
109
110         in_set_state--;
111
112         _splicing  = other->_splicing;
113         _nudging   = other->_nudging;
114         _edit_mode = other->_edit_mode;
115
116         in_set_state = 0;
117         in_flush = false;
118         in_partition = false;
119         subcnt = 0;
120         _read_data_count = 0;
121         _frozen = other->_frozen;
122         
123         layer_op_counter = other->layer_op_counter;
124         freeze_length = other->freeze_length;
125 }
126
127 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
128         : _name (str), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
129 {
130         RegionLock rlock2 (const_cast<Playlist*> (other.get()));
131
132         nframes_t end = start + cnt - 1;
133
134         init (hide);
135
136         in_set_state++;
137
138         for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
139
140                 boost::shared_ptr<Region> region;
141                 boost::shared_ptr<Region> new_region;
142                 nframes_t offset = 0;
143                 nframes_t position = 0;
144                 nframes_t len = 0;
145                 string    new_name;
146                 OverlapType overlap;
147
148                 region = *i;
149
150                 overlap = region->coverage (start, end);
151
152                 switch (overlap) {
153                 case OverlapNone:
154                         continue;
155
156                 case OverlapInternal:
157                         offset = start - region->position();
158                         position = 0;
159                         len = cnt;
160                         break;
161
162                 case OverlapStart:
163                         offset = 0;
164                         position = region->position() - start;
165                         len = end - region->position();
166                         break;
167
168                 case OverlapEnd:
169                         offset = start - region->position();
170                         position = 0;
171                         len = region->length() - offset;
172                         break;
173
174                 case OverlapExternal:
175                         offset = 0;
176                         position = region->position() - start;
177                         len = region->length();
178                         break;
179                 }
180
181                 _session.region_name (new_name, region->name(), false);
182
183                 new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
184
185                 add_region_internal (new_region, position);
186         }
187         
188         in_set_state--;
189
190         /* this constructor does NOT notify others (session) */
191 }
192
193 void
194 Playlist::use ()
195 {
196         ++_refcnt;
197         InUse (true); /* EMIT SIGNAL */
198 }
199
200 void
201 Playlist::release ()
202 {
203         if (_refcnt > 0) {
204                 _refcnt--; 
205         }
206
207         if (_refcnt == 0) {
208                 InUse (false); /* EMIT SIGNAL */
209         }
210 }
211
212
213 void
214 Playlist::copy_regions (RegionList& newlist) const
215 {
216         RegionLock rlock (const_cast<Playlist *> (this));
217
218         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
219                 newlist.push_back (RegionFactory::RegionFactory::create (*i));
220         }
221 }
222
223 void
224 Playlist::init (bool hide)
225 {
226         g_atomic_int_set (&block_notifications, 0);
227         g_atomic_int_set (&ignore_state_changes, 0);
228         pending_modified = false;
229         pending_length = false;
230         _refcnt = 0;
231         _hidden = hide;
232         _splicing = false;
233         _nudging = false;
234         in_set_state = 0;
235         _edit_mode = Config->get_edit_mode();
236         in_flush = false;
237         in_partition = false;
238         subcnt = 0;
239         _read_data_count = 0;
240         _frozen = false;
241         layer_op_counter = 0;
242         freeze_length = 0;
243
244         Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
245 }
246
247 Playlist::Playlist (const Playlist& pl)
248         : _session (pl._session)
249         , _type(pl.data_type())
250 {
251         fatal << _("playlist const copy constructor called") << endmsg;
252 }
253
254 Playlist::Playlist (Playlist& pl)
255         : _session (pl._session)
256         , _type(pl.data_type())
257 {
258         fatal << _("playlist non-const copy constructor called") << endmsg;
259 }
260
261 Playlist::~Playlist ()
262 {
263         { 
264                 RegionLock rl (this);
265
266                 for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
267                         (*i)->set_playlist (boost::shared_ptr<Playlist>());
268                 }
269         }
270
271         /* GoingAway must be emitted by derived classes */
272 }
273
274 void
275 Playlist::set_name (string str)
276 {
277         /* in a typical situation, a playlist is being used
278            by one diskstream and also is referenced by the
279            Session. if there are more references than that,
280            then don't change the name.
281         */
282
283         if (_refcnt > 2) {
284                 return;
285         }
286
287         _name = str; 
288         NameChanged(); /* EMIT SIGNAL */
289 }
290
291 /***********************************************************************
292  CHANGE NOTIFICATION HANDLING
293  
294  Notifications must be delayed till the region_lock is released. This
295  is necessary because handlers for the signals may need to acquire
296  the lock (e.g. to read from the playlist).
297  ***********************************************************************/
298
299 void
300 Playlist::freeze ()
301 {
302         delay_notifications ();
303         g_atomic_int_inc (&ignore_state_changes);
304 }
305
306 void
307 Playlist::thaw ()
308 {
309         g_atomic_int_dec_and_test (&ignore_state_changes);
310         release_notifications ();
311 }
312
313
314 void
315 Playlist::delay_notifications ()
316 {
317         g_atomic_int_inc (&block_notifications);
318         freeze_length = _get_maximum_extent();
319 }
320
321 void
322 Playlist::release_notifications ()
323 {
324         if (g_atomic_int_dec_and_test (&block_notifications)) { 
325                 flush_notifications ();
326         } 
327 }
328
329
330 void
331 Playlist::notify_modified ()
332 {
333         if (holding_state ()) {
334                 pending_modified = true;
335         } else {
336                 pending_modified = false;
337                 Modified(); /* EMIT SIGNAL */
338         }
339 }
340
341 void
342 Playlist::notify_region_removed (boost::shared_ptr<Region> r)
343 {
344         if (holding_state ()) {
345                 pending_removes.insert (r);
346                 pending_modified = true;
347                 pending_length = true;
348         } else {
349                 /* this might not be true, but we have to act
350                    as though it could be.
351                 */
352                 LengthChanged (); /* EMIT SIGNAL */
353                 Modified (); /* EMIT SIGNAL */
354         }
355 }
356
357 void
358 Playlist::notify_region_added (boost::shared_ptr<Region> r)
359 {
360         /* the length change might not be true, but we have to act
361            as though it could be.
362         */
363
364         if (holding_state()) {
365                 pending_adds.insert (r);
366                 pending_modified = true;
367                 pending_length = true;
368         } else {
369                 LengthChanged (); /* EMIT SIGNAL */
370                 Modified (); /* EMIT SIGNAL */
371         }
372 }
373
374 void
375 Playlist::notify_length_changed ()
376 {
377         if (holding_state ()) {
378                 pending_length = true;
379         } else {
380                 LengthChanged(); /* EMIT SIGNAL */
381                 Modified (); /* EMIT SIGNAL */
382         }
383 }
384
385 void
386 Playlist::flush_notifications ()
387 {
388         set<boost::shared_ptr<Region> > dependent_checks_needed;
389         set<boost::shared_ptr<Region> >::iterator s;
390         uint32_t n = 0;
391
392         if (in_flush) {
393                 return;
394         }
395
396         in_flush = true;
397
398         /* we have no idea what order the regions ended up in pending
399            bounds (it could be based on selection order, for example).
400            so, to preserve layering in the "most recently moved is higher" 
401            model, sort them by existing layer, then timestamp them.
402         */
403
404         // RegionSortByLayer cmp;
405         // pending_bounds.sort (cmp);
406
407         for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
408                 if (Config->get_layer_model() == MoveAddHigher) {
409                         timestamp_layer_op (*r);
410                 }
411                 pending_length = true;
412                 dependent_checks_needed.insert (*r);
413                 n++;
414         }
415
416         for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
417                 dependent_checks_needed.insert (*s);
418                 n++;
419         }
420
421         for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
422                 remove_dependents (*s);
423                 n++;
424         }
425
426         if ((freeze_length != _get_maximum_extent()) || pending_length) {
427                 pending_length = 0;
428                 LengthChanged(); /* EMIT SIGNAL */
429                 n++;
430         }
431
432         if (n || pending_modified) {
433                 if (!in_set_state) {
434                         possibly_splice ();
435                         relayer ();
436                 }
437                 pending_modified = false;
438                 Modified (); /* EMIT SIGNAL */
439         }
440
441         for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
442                 check_dependents (*s, false);
443         }
444
445         pending_adds.clear ();
446         pending_removes.clear ();
447         pending_bounds.clear ();
448
449         in_flush = false;
450 }
451
452 /*************************************************************
453   PLAYLIST OPERATIONS
454  *************************************************************/
455
456 void
457 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times) 
458
459         RegionLock rlock (this);
460         
461         times = fabs (times);
462         
463         int itimes = (int) floor (times);
464
465         nframes_t pos = position;
466         
467         if (itimes >= 1) {
468                 add_region_internal (region, pos);
469                 pos += region->length();
470                 --itimes;
471         }
472         
473         /* later regions will all be spliced anyway */
474         
475         if (!holding_state ()) {
476                 possibly_splice_unlocked ();
477         }
478
479         /* note that itimes can be zero if we being asked to just
480            insert a single fraction of the region.
481         */
482
483         for (int i = 0; i < itimes; ++i) {
484                 boost::shared_ptr<Region> copy = RegionFactory::create (region);
485                 add_region_internal (copy, pos);
486                 pos += region->length();
487         }
488         
489         if (floor (times) != times) {
490                 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
491                 string name;
492                 _session.region_name (name, region->name(), false);
493                 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
494                 add_region_internal (sub, pos);
495         }
496 }
497
498 void
499 Playlist::set_region_ownership ()
500 {
501         RegionLock rl (this);
502         RegionList::iterator i;
503         boost::weak_ptr<Playlist> pl (shared_from_this());
504
505         for (i = regions.begin(); i != regions.end(); ++i) {
506                 (*i)->set_playlist (pl);
507         }
508 }
509
510 void
511 Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
512 {
513         RegionSortByPosition cmp;
514         nframes_t old_length = 0;
515
516         if (!holding_state()) {
517                  old_length = _get_maximum_extent();
518         }
519
520         if (!in_set_state) {
521                 boost::shared_ptr<Playlist> foo (shared_from_this());
522                 region->set_playlist (boost::weak_ptr<Playlist>(foo));
523         }
524
525         region->set_position (position, this);
526
527         timestamp_layer_op (region);
528
529         regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
530         all_regions.insert (region);
531
532         if (!holding_state () && !in_set_state) {
533                 /* layers get assigned from XML state */
534                 relayer ();
535         }
536
537         /* we need to notify the existence of new region before checking dependents. Ick. */
538
539         notify_region_added (region);
540         
541         if (!holding_state ()) {
542                 check_dependents (region, false);
543                 if (old_length != _get_maximum_extent()) {
544                         notify_length_changed ();
545                 }
546         }
547
548         region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy), 
549                                                   boost::weak_ptr<Region> (region)));
550 }
551
552 void
553 Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos)
554 {
555         RegionLock rlock (this);
556
557         remove_region_internal (old);
558         add_region_internal (newr, pos);
559
560         if (!holding_state ()) {
561                 possibly_splice_unlocked ();
562         }
563 }
564
565 void
566 Playlist::remove_region (boost::shared_ptr<Region> region)
567 {
568         RegionLock rlock (this);
569         remove_region_internal (region);
570
571         if (!holding_state ()) {
572                 possibly_splice_unlocked ();
573         }
574 }
575
576 int
577 Playlist::remove_region_internal (boost::shared_ptr<Region>region)
578 {
579         RegionList::iterator i;
580         nframes_t old_length = 0;
581
582         if (!holding_state()) {
583                 old_length = _get_maximum_extent();
584         }
585
586         for (i = regions.begin(); i != regions.end(); ++i) {
587                 if (*i == region) {
588
589                         regions.erase (i);
590
591                         if (!holding_state ()) {
592                                 relayer ();
593                                 remove_dependents (region);
594                                 
595                                 if (old_length != _get_maximum_extent()) {
596                                         notify_length_changed ();
597                                 }
598                         }
599
600                         notify_region_removed (region);
601                         return 0;
602                 }
603         }
604         return -1;
605 }
606
607 void
608 Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
609 {
610         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
611                 if (Config->get_use_overlap_equivalency()) {
612                         if ((*i)->overlap_equivalent (other)) {
613                                 results.push_back ((*i));
614                         } else if ((*i)->equivalent (other)) {
615                                 results.push_back ((*i));
616                         }
617                 }
618         }
619 }
620
621 void
622 Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
623 {
624         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
625
626                 if ((*i) && (*i)->region_list_equivalent (other)) {
627                         results.push_back (*i);
628                 }
629         }
630 }
631
632 void
633 Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
634 {
635         RegionList thawlist;
636
637         partition_internal (start, end, false, thawlist);
638
639         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
640                 (*i)->thaw ("separation");
641         }
642 }
643
644 void
645 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
646 {
647         RegionLock rlock (this);
648         boost::shared_ptr<Region> region;
649         boost::shared_ptr<Region> current;
650         string new_name;
651         RegionList::iterator tmp;
652         OverlapType overlap;
653         nframes_t pos1, pos2, pos3, pos4;
654         RegionList new_regions;
655
656         in_partition = true;
657
658         /* need to work from a copy, because otherwise the regions we add during the process
659            get operated on as well.
660         */
661
662         RegionList copy = regions;
663
664         for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
665                 
666                 tmp = i;
667                 ++tmp;
668
669                 current = *i;
670                 
671                 if (current->first_frame() == start && current->last_frame() == end) {
672                         if (cutting) {
673                                 remove_region_internal (current);
674                         }
675                         continue;
676                 }
677                 
678                 if ((overlap = current->coverage (start, end)) == OverlapNone) {
679                         continue;
680                 }
681                 
682                 pos1 = current->position();
683                 pos2 = start;
684                 pos3 = end;
685                 pos4 = current->last_frame();
686
687                 if (overlap == OverlapInternal) {
688                         
689                         /* split: we need 3 new regions, the front, middle and end.
690                            cut:   we need 2 regions, the front and end.
691                         */
692                         
693                         /*
694                                          start                 end
695                           ---------------*************************------------
696                                          P1  P2              P3  P4
697                           SPLIT:
698                           ---------------*****++++++++++++++++====------------
699                           CUT
700                           ---------------*****----------------====------------
701                           
702                         */
703
704                         if (!cutting) {
705                                 
706                                 /* "middle" ++++++ */
707                                 
708                                 _session.region_name (new_name, current->name(), false);
709                                 region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
710                                                        regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
711                                 add_region_internal (region, start);
712                                 new_regions.push_back (region);
713                         }
714                         
715                         /* "end" ====== */
716                         
717                         _session.region_name (new_name, current->name(), false);
718                         region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name, 
719                                                regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
720
721                         add_region_internal (region, end);
722                         new_regions.push_back (region);
723
724                         /* "front" ***** */
725                                 
726                         current->freeze ();
727                         thawlist.push_back (current);
728                         current->trim_end (pos2, this);
729
730                 } else if (overlap == OverlapEnd) {
731
732                         /*
733                                                               start           end
734                                     ---------------*************************------------
735                                                    P1           P2         P4   P3
736                                     SPLIT:                                                 
737                                     ---------------**************+++++++++++------------
738                                     CUT:                                                   
739                                     ---------------**************-----------------------
740
741                         */
742
743                         if (!cutting) {
744                                 
745                                 /* end +++++ */
746                                 
747                                 _session.region_name (new_name, current->name(), false);
748                                 region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
749                                                        Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
750                                 add_region_internal (region, start);
751                                 new_regions.push_back (region);
752                         }
753
754                         /* front ****** */
755
756                         current->freeze ();
757                         thawlist.push_back (current);
758                         current->trim_end (pos2, this);
759
760                 } else if (overlap == OverlapStart) {
761
762                         /* split: we need 2 regions: the front and the end.
763                            cut: just trim current to skip the cut area
764                         */
765                                 
766                         /*
767                                                         start           end
768                                     ---------------*************************------------
769                                        P2          P1 P3                   P4          
770
771                                     SPLIT:
772                                     ---------------****+++++++++++++++++++++------------
773                                     CUT:
774                                     -------------------*********************------------
775                                     
776                         */
777
778                         if (!cutting) {
779                                 
780                                 /* front **** */
781                                  _session.region_name (new_name, current->name(), false);
782                                  region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
783                                                         regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
784                                  add_region_internal (region, pos1);
785                                  new_regions.push_back (region);
786                         } 
787                         
788                         /* end */
789                         
790                         current->freeze ();
791                         thawlist.push_back (current);
792                         current->trim_front (pos3, this);
793
794                 } else if (overlap == OverlapExternal) {
795
796                         /* split: no split required.
797                            cut: remove the region.
798                         */
799                                 
800                         /*
801                                        start                                      end
802                                     ---------------*************************------------
803                                        P2          P1 P3                   P4          
804
805                                     SPLIT:
806                                     ---------------*************************------------
807                                     CUT:
808                                     ----------------------------------------------------
809                                     
810                         */
811
812                         if (cutting) {
813                                 remove_region_internal (current);
814                         }
815                         new_regions.push_back (current);
816                 }
817         }
818
819         in_partition = false;
820
821         for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
822                 check_dependents (*i, false);
823         }
824 }
825
826 boost::shared_ptr<Playlist>
827 Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
828 {
829         boost::shared_ptr<Playlist> ret;
830         boost::shared_ptr<Playlist> pl;
831         nframes_t start;
832
833         if (ranges.empty()) {
834                 return boost::shared_ptr<Playlist>();
835         }
836
837         start = ranges.front().start;
838
839         for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
840
841                 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
842                 
843                 if (i == ranges.begin()) {
844                         ret = pl;
845                 } else {
846                         
847                         /* paste the next section into the nascent playlist,
848                            offset to reflect the start of the first range we
849                            chopped.
850                         */
851
852                         ret->paste (pl, (*i).start - start, 1.0f);
853                 }
854         }
855
856         return ret;
857 }
858
859 boost::shared_ptr<Playlist>
860 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
861 {
862         boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
863         return cut_copy (pmf, ranges, result_is_hidden);
864 }
865
866 boost::shared_ptr<Playlist>
867 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
868 {
869         boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
870         return cut_copy (pmf, ranges, result_is_hidden);
871 }
872
873 boost::shared_ptr<Playlist>
874 Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
875 {
876         boost::shared_ptr<Playlist> the_copy;
877         RegionList thawlist;
878         char buf[32];
879
880         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
881         string new_name = _name;
882         new_name += '.';
883         new_name += buf;
884
885         if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
886                 return boost::shared_ptr<Playlist>();
887         }
888
889         partition_internal (start, start+cnt-1, true, thawlist);
890         possibly_splice ();
891
892         for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
893                 (*i)->thaw ("playlist cut");
894         }
895
896         return the_copy;
897 }
898
899 boost::shared_ptr<Playlist>
900 Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
901 {
902         char buf[32];
903         
904         snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
905         string new_name = _name;
906         new_name += '.';
907         new_name += buf;
908
909         cnt = min (_get_maximum_extent() - start, cnt);
910         return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
911 }
912
913 int
914 Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
915 {
916         times = fabs (times);
917         nframes_t old_length;
918
919         {
920                 RegionLock rl1 (this);
921                 RegionLock rl2 (other.get());
922
923                 old_length = _get_maximum_extent();
924         
925                 int itimes = (int) floor (times);
926                 nframes_t pos = position;
927                 nframes_t shift = other->_get_maximum_extent();
928                 layer_t top_layer = regions.size();
929
930                 while (itimes--) {
931                         for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
932                                 boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
933
934                                 /* put these new regions on top of all existing ones, but preserve
935                                    the ordering they had in the original playlist.
936                                 */
937                                 
938                                 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
939                                 add_region_internal (copy_of_region, copy_of_region->position() + pos);
940                         }
941                         pos += shift;
942                 }
943
944                 possibly_splice_unlocked ();
945
946                 /* XXX shall we handle fractional cases at some point? */
947
948                 if (old_length != _get_maximum_extent()) {
949                         notify_length_changed ();
950                 }
951
952                 
953         }
954
955         return 0;
956 }
957
958
959 void
960 Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float times)
961 {
962         times = fabs (times);
963
964         RegionLock rl (this);
965         int itimes = (int) floor (times);
966         nframes_t pos = position;
967
968         while (itimes--) {
969                 boost::shared_ptr<Region> copy = RegionFactory::create (region);
970                 add_region_internal (copy, pos);
971                 pos += region->length();
972         }
973
974         if (floor (times) != times) {
975                 nframes_t length = (nframes_t) floor (region->length() * (times - floor (times)));
976                 string name;
977                 _session.region_name (name, region->name(), false);
978                 boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
979                 add_region_internal (sub, pos);
980         }
981 }
982
983 void
984 Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_position)
985 {
986         RegionLock rl (this);
987
988         if (!region->covers (playlist_position)) {
989                 return;
990         }
991
992         if (region->position() == playlist_position ||
993             region->last_frame() == playlist_position) {
994                 return;
995         }
996
997         boost::shared_ptr<Region> left;
998         boost::shared_ptr<Region> right;
999         nframes_t before;
1000         nframes_t after;
1001         string before_name;
1002         string after_name;
1003
1004         before = playlist_position - region->position();
1005         after = region->length() - before;
1006         
1007         
1008         _session.region_name (before_name, region->name(), false);
1009         left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit));
1010
1011         _session.region_name (after_name, region->name(), false);
1012         right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
1013
1014         add_region_internal (left, region->position());
1015         add_region_internal (right, region->position() + before);
1016         
1017         uint64_t orig_layer_op = region->last_layer_op();
1018         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1019                 if ((*i)->last_layer_op() > orig_layer_op) {
1020                         (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1021                 }
1022         }
1023         
1024         left->set_last_layer_op ( orig_layer_op );
1025         right->set_last_layer_op ( orig_layer_op + 1);
1026
1027         layer_op_counter++;
1028
1029         finalize_split_region (region, left, right);
1030         
1031         if (remove_region_internal (region)) {
1032                 return;
1033         }
1034 }
1035
1036 void
1037 Playlist::possibly_splice ()
1038 {
1039         if (_edit_mode == Splice) {
1040                 splice_locked ();
1041         }
1042 }
1043
1044 void
1045 Playlist::possibly_splice_unlocked ()
1046 {
1047         if (_edit_mode == Splice) {
1048                 splice_unlocked ();
1049         }
1050 }
1051
1052 void
1053 Playlist::splice_locked ()
1054 {
1055         {
1056                 RegionLock rl (this);
1057                 core_splice ();
1058         }
1059
1060         notify_length_changed ();
1061 }
1062
1063 void
1064 Playlist::splice_unlocked ()
1065 {
1066         core_splice ();
1067         notify_length_changed ();
1068 }
1069
1070 void
1071 Playlist::core_splice ()
1072 {
1073         _splicing = true;
1074         
1075         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1076                 
1077                 RegionList::iterator next;
1078                 
1079                 next = i;
1080                 ++next;
1081                 
1082                 if (next == regions.end()) {
1083                         break;
1084                 }
1085                 
1086                 (*next)->set_position ((*i)->last_frame() + 1, this);
1087         }
1088         
1089         _splicing = false;
1090 }
1091
1092 void
1093 Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region> region)
1094 {
1095         if (in_set_state || _splicing || _nudging) {
1096                 return;
1097         }
1098
1099         if (what_changed & ARDOUR::PositionChanged) {
1100
1101                 /* remove it from the list then add it back in
1102                    the right place again.
1103                 */
1104                 
1105                 RegionSortByPosition cmp;
1106
1107                 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1108                 
1109                 if (i == regions.end()) {
1110                         warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1111                                             _name, region->name())
1112                                 << endmsg;
1113                         return;
1114                 }
1115
1116                 regions.erase (i);
1117                 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
1118
1119         }
1120
1121         if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1122                 if (holding_state ()) {
1123                         pending_bounds.push_back (region);
1124                 } else {
1125                         if (Config->get_layer_model() == MoveAddHigher) {
1126                                 /* it moved or changed length, so change the timestamp */
1127                                 timestamp_layer_op (region);
1128                         }
1129                         
1130                         possibly_splice ();
1131                         notify_length_changed ();
1132                         relayer ();
1133                         check_dependents (region, false);
1134                 }
1135         }
1136 }
1137
1138 void
1139 Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> weak_region)
1140 {
1141         boost::shared_ptr<Region> region (weak_region.lock());
1142
1143         if (!region) {
1144                 return;
1145         }
1146
1147
1148         /* this makes a virtual call to the right kind of playlist ... */
1149
1150         region_changed (what_changed, region);
1151 }
1152
1153 bool
1154 Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
1155 {
1156         Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1157         bool save = false;
1158
1159         if (in_set_state || in_flush) {
1160                 return false;
1161         }
1162
1163         {
1164                 if (what_changed & BoundsChanged) {
1165                         region_bounds_changed (what_changed, region);
1166                         save = !(_splicing || _nudging);
1167                 }
1168                 
1169                 if ((what_changed & Region::MuteChanged) && 
1170                     !(what_changed &  Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1171                         check_dependents (region, false);
1172                 }
1173                 
1174                 if (what_changed & our_interests) {
1175                         save = true;
1176                 }
1177         }
1178
1179         return save;
1180 }
1181
1182 void
1183 Playlist::clear (bool with_signals)
1184 {
1185         { 
1186                 RegionLock rl (this);
1187                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1188                         pending_removes.insert (*i);
1189                 }
1190                 regions.clear ();
1191         }
1192
1193         if (with_signals) {
1194                 LengthChanged ();
1195                 Modified ();
1196         }
1197
1198 }
1199
1200 /***********************************************************************
1201  FINDING THINGS
1202  **********************************************************************/
1203
1204 Playlist::RegionList *
1205 Playlist::regions_at (nframes_t frame)
1206
1207 {
1208         RegionLock rlock (this);
1209         return find_regions_at (frame);
1210 }       
1211
1212 boost::shared_ptr<Region>
1213 Playlist::top_region_at (nframes_t frame)
1214
1215 {
1216         RegionLock rlock (this);
1217         RegionList *rlist = find_regions_at (frame);
1218         boost::shared_ptr<Region> region;
1219         
1220         if (rlist->size()) {
1221                 RegionSortByLayer cmp;
1222                 rlist->sort (cmp);
1223                 region = rlist->back();
1224         } 
1225
1226         delete rlist;
1227         return region;
1228 }       
1229
1230 Playlist::RegionList *
1231 Playlist::find_regions_at (nframes_t frame)
1232 {
1233         RegionList *rlist = new RegionList;
1234
1235         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1236                 if ((*i)->covers (frame)) {
1237                         rlist->push_back (*i);
1238                 }
1239         }
1240
1241         return rlist;
1242 }
1243
1244 Playlist::RegionList *
1245 Playlist::regions_touched (nframes_t start, nframes_t end)
1246 {
1247         RegionLock rlock (this);
1248         RegionList *rlist = new RegionList;
1249
1250         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1251                 if ((*i)->coverage (start, end) != OverlapNone) {
1252                         rlist->push_back (*i);
1253                 }
1254         }
1255
1256         return rlist;
1257 }
1258
1259
1260 boost::shared_ptr<Region>
1261 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1262 {
1263         RegionLock rlock (this);
1264         boost::shared_ptr<Region> ret;
1265         nframes_t closest = max_frames;
1266
1267
1268         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1269
1270                 nframes_t distance;
1271                 boost::shared_ptr<Region> r = (*i);
1272                 nframes_t pos = 0;
1273
1274                 switch (point) {
1275                 case Start:
1276                         pos = r->first_frame ();
1277                         break;
1278                 case End:
1279                         pos = r->last_frame ();
1280                         break;
1281                 case SyncPoint:
1282                         pos = r->adjust_to_sync (r->first_frame());
1283                         break;
1284                 }
1285
1286                 switch (dir) {
1287                 case 1: /* forwards */
1288
1289                         if (pos >= frame) {
1290                                 if ((distance = pos - frame) < closest) {
1291                                         closest = distance;
1292                                         ret = r;
1293                                 }
1294                         }
1295
1296                         break;
1297
1298                 default: /* backwards */
1299
1300                         if (pos <= frame) {
1301                                 if ((distance = frame - pos) < closest) {
1302                                         closest = distance;
1303                                         ret = r;
1304                                 }
1305                         }
1306                         break;
1307                 }
1308         }
1309
1310         return ret;
1311 }
1312
1313 /***********************************************************************/
1314
1315
1316
1317 void
1318 Playlist::mark_session_dirty ()
1319 {
1320         if (!in_set_state && !holding_state ()) {
1321                 _session.set_dirty();
1322         }
1323 }
1324
1325 int
1326 Playlist::set_state (const XMLNode& node)
1327 {
1328         XMLNode *child;
1329         XMLNodeList nlist;
1330         XMLNodeConstIterator niter;
1331         XMLPropertyList plist;
1332         XMLPropertyConstIterator piter;
1333         XMLProperty *prop;
1334         boost::shared_ptr<Region> region;
1335         string region_name;
1336
1337         in_set_state++;
1338
1339         if (node.name() != "Playlist") {
1340                 in_set_state--;
1341                 return -1;
1342         }
1343
1344         freeze ();
1345
1346         plist = node.properties();
1347
1348         for (piter = plist.begin(); piter != plist.end(); ++piter) {
1349
1350                 prop = *piter;
1351                 
1352                 if (prop->name() == X_("name")) {
1353                         _name = prop->value();
1354                 } else if (prop->name() == X_("orig_diskstream_id")) {
1355                         _orig_diskstream_id = prop->value ();
1356                 } else if (prop->name() == X_("frozen")) {
1357                         _frozen = (prop->value() == X_("yes"));
1358                 }
1359         }
1360
1361         clear (false);
1362         
1363         nlist = node.children();
1364
1365         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1366
1367                 child = *niter;
1368                 
1369                 if (child->name() == "Region") {
1370
1371                         if ((prop = child->property ("id")) == 0) {
1372                                 error << _("region state node has no ID, ignored") << endmsg;
1373                                 continue;
1374                         }
1375                         
1376                         ID id = prop->value ();
1377                         
1378                         if ((region = region_by_id (id))) {
1379
1380                                 Change what_changed = Change (0);
1381
1382                                 if (region->set_live_state (*child, what_changed, true)) {
1383                                         error << _("Playlist: cannot reset region state from XML") << endmsg;
1384                                         continue;
1385                                 }
1386
1387                         } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1388                                 error << _("Playlist: cannot create region from XML") << endmsg;
1389                                 continue;
1390                         }
1391
1392                         add_region (region, region->position(), 1.0);
1393
1394                         // So that layer_op ordering doesn't get screwed up
1395                         region->set_last_layer_op( region->layer());
1396
1397                 }                       
1398         }
1399         
1400         notify_modified ();
1401
1402         thaw ();
1403
1404         /* update dependents, which was not done during add_region_internal 
1405            due to in_set_state being true 
1406         */
1407
1408         for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1409                 check_dependents (*r, false);
1410         }
1411
1412         in_set_state--;
1413
1414         return 0;
1415 }
1416
1417 XMLNode&
1418 Playlist::get_state()
1419 {
1420         return state(true);
1421 }
1422
1423 XMLNode&
1424 Playlist::get_template()
1425 {
1426         return state(false);
1427 }
1428
1429 XMLNode&
1430 Playlist::state (bool full_state)
1431 {
1432         XMLNode *node = new XMLNode (X_("Playlist"));
1433         char buf[64];
1434         
1435         node->add_property (X_("name"), _name);
1436         node->add_property (X_("type"), _type.to_string());
1437
1438         _orig_diskstream_id.print (buf, sizeof (buf));
1439         node->add_property (X_("orig_diskstream_id"), buf);
1440         node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1441
1442         if (full_state) {
1443                 RegionLock rlock (this, false);
1444
1445                 cerr << _name << " getting region state for " << regions.size() << endl;
1446
1447                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1448                         cerr << "\t" << " now at " << (*i) << endl;
1449                         cerr << "\t\t" << (*i)->name() << endl;
1450                         node->add_child_nocopy ((*i)->get_state());
1451                 }
1452         }
1453
1454         if (_extra_xml) {
1455                 node->add_child_copy (*_extra_xml);
1456         }
1457
1458         return *node;
1459 }
1460
1461 bool
1462 Playlist::empty() const
1463 {
1464         RegionLock rlock (const_cast<Playlist *>(this), false);
1465         return regions.empty();
1466 }
1467
1468 uint32_t
1469 Playlist::n_regions() const
1470 {
1471         RegionLock rlock (const_cast<Playlist *>(this), false);
1472         return regions.size();
1473 }
1474
1475 nframes_t
1476 Playlist::get_maximum_extent () const
1477 {
1478         RegionLock rlock (const_cast<Playlist *>(this), false);
1479         return _get_maximum_extent ();
1480 }
1481
1482 ARDOUR::nframes_t
1483 Playlist::_get_maximum_extent () const
1484 {
1485         RegionList::const_iterator i;
1486         nframes_t max_extent = 0;
1487         nframes_t end = 0;
1488
1489         for (i = regions.begin(); i != regions.end(); ++i) {
1490                 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1491                         max_extent = end;
1492                 }
1493         }
1494
1495         return max_extent;
1496 }
1497
1498 string 
1499 Playlist::bump_name (string name, Session &session)
1500 {
1501         string newname = name;
1502
1503         do {
1504                 newname = Playlist::bump_name_once (newname);
1505         } while (session.playlist_by_name (newname)!=NULL);
1506
1507         return newname;
1508 }
1509
1510 string
1511 Playlist::bump_name_once (string name)
1512 {
1513         string::size_type period;
1514         string newname;
1515
1516         if ((period = name.find_last_of ('.')) == string::npos) {
1517                 newname = name;
1518                 newname += ".1";
1519         } else {
1520                 char buf[32];
1521                 int version;
1522                 
1523                 sscanf (name.substr (period+1).c_str(), "%d", &version);
1524                 snprintf (buf, sizeof(buf), "%d", version+1);
1525                 
1526                 newname = name.substr (0, period+1);
1527                 newname += buf;
1528         }
1529
1530         return newname;
1531 }
1532
1533 layer_t
1534 Playlist::top_layer() const
1535 {
1536         RegionLock rlock (const_cast<Playlist *> (this));
1537         layer_t top = 0;
1538
1539         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1540                 top = max (top, (*i)->layer());
1541         }
1542         return top;
1543 }
1544
1545 void
1546 Playlist::set_edit_mode (EditMode mode)
1547 {
1548         _edit_mode = mode;
1549 }
1550
1551 /********************
1552  * Region Layering
1553  ********************/
1554
1555 void
1556 Playlist::relayer ()
1557 {
1558         RegionList::iterator i;
1559         uint32_t layer = 0;
1560
1561         /* don't send multiple Modified notifications
1562            when multiple regions are relayered.
1563         */
1564
1565         freeze ();
1566
1567         if (Config->get_layer_model() == MoveAddHigher || 
1568             Config->get_layer_model() == AddHigher) {
1569
1570                 RegionSortByLastLayerOp cmp;
1571                 RegionList copy = regions;
1572
1573                 copy.sort (cmp);
1574
1575                 for (i = copy.begin(); i != copy.end(); ++i) {
1576                         (*i)->set_layer (layer++);
1577                 }
1578
1579         } else {
1580                 
1581                 /* Session::LaterHigher model */
1582
1583                 for (i = regions.begin(); i != regions.end(); ++i) {
1584                         (*i)->set_layer (layer++);
1585                 }
1586         }
1587
1588         /* sending Modified means that various kinds of layering
1589            models operate correctly at the GUI
1590            level. slightly inefficient, but only slightly.
1591
1592            We force a Modified signal here in case no layers actually
1593            changed.
1594         */
1595
1596         notify_modified ();
1597
1598         thaw ();
1599 }
1600
1601 /* XXX these layer functions are all deprecated */
1602
1603 void
1604 Playlist::raise_region (boost::shared_ptr<Region> region)
1605 {
1606         uint32_t rsz = regions.size();
1607         layer_t target = region->layer() + 1U;
1608
1609         if (target >= rsz) {
1610                 /* its already at the effective top */
1611                 return;
1612         }
1613
1614         move_region_to_layer (target, region, 1);
1615 }
1616
1617 void
1618 Playlist::lower_region (boost::shared_ptr<Region> region)
1619 {
1620         if (region->layer() == 0) {
1621                 /* its already at the bottom */
1622                 return;
1623         }
1624
1625         layer_t target = region->layer() - 1U;
1626
1627         move_region_to_layer (target, region, -1);
1628 }
1629
1630 void
1631 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
1632 {
1633         /* does nothing useful if layering mode is later=higher */
1634         if ((Config->get_layer_model() == MoveAddHigher) ||
1635             (Config->get_layer_model() == AddHigher)) {
1636                 timestamp_layer_op (region);
1637                 relayer ();
1638         }
1639 }
1640
1641 void
1642 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
1643 {
1644         /* does nothing useful if layering mode is later=higher */
1645         if ((Config->get_layer_model() == MoveAddHigher) ||
1646             (Config->get_layer_model() == AddHigher)) {
1647                 region->set_last_layer_op (0);
1648                 relayer ();
1649         }
1650 }
1651
1652 int
1653 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
1654 {
1655         RegionList::iterator i;
1656         typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
1657         list<LayerInfo> layerinfo;
1658         layer_t dest;
1659
1660         {
1661                 RegionLock rlock (const_cast<Playlist *> (this));
1662                 
1663                 for (i = regions.begin(); i != regions.end(); ++i) {
1664                         
1665                         if (region == *i) {
1666                                 continue;
1667                         }
1668
1669                         if (dir > 0) {
1670
1671                                 /* region is moving up, move all regions on intermediate layers
1672                                    down 1
1673                                 */
1674                                 
1675                                 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
1676                                         dest = (*i)->layer() - 1;
1677                                 } else {
1678                                         /* not affected */
1679                                         continue;
1680                                 }
1681                         } else {
1682
1683                                 /* region is moving down, move all regions on intermediate layers
1684                                    up 1
1685                                 */
1686
1687                                 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
1688                                         dest = (*i)->layer() + 1;
1689                                 } else {
1690                                         /* not affected */
1691                                         continue;
1692                                 }
1693                         }
1694
1695                         LayerInfo newpair;
1696                         
1697                         newpair.first = *i;
1698                         newpair.second = dest;
1699                         
1700                         layerinfo.push_back (newpair);
1701                 } 
1702         }
1703
1704         /* now reset the layers without holding the region lock */
1705
1706         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1707                 x->first->set_layer (x->second);
1708         }
1709
1710         region->set_layer (target_layer);
1711
1712         /* now check all dependents */
1713
1714         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1715                 check_dependents (x->first, false);
1716         }
1717         
1718         check_dependents (region, false);
1719         
1720         return 0;
1721 }
1722
1723 void
1724 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
1725 {
1726         RegionList::iterator i;
1727         nframes_t new_pos;
1728         bool moved = false;
1729
1730         _nudging = true;
1731
1732         {
1733                 RegionLock rlock (const_cast<Playlist *> (this));
1734                 
1735                 for (i = regions.begin(); i != regions.end(); ++i) {
1736
1737                         if ((*i)->position() >= start) {
1738
1739                                 if (forwards) {
1740
1741                                         if ((*i)->last_frame() > max_frames - distance) {
1742                                                 new_pos = max_frames - (*i)->length();
1743                                         } else {
1744                                                 new_pos = (*i)->position() + distance;
1745                                         }
1746                                         
1747                                 } else {
1748                                         
1749                                         if ((*i)->position() > distance) {
1750                                                 new_pos = (*i)->position() - distance;
1751                                         } else {
1752                                                 new_pos = 0;
1753                                         }
1754                                 }
1755
1756                                 (*i)->set_position (new_pos, this);
1757                                 moved = true;
1758                         }
1759                 }
1760         }
1761
1762         if (moved) {
1763                 _nudging = false;
1764                 notify_length_changed ();
1765         }
1766
1767 }
1768
1769 boost::shared_ptr<Region>
1770 Playlist::find_region (const ID& id) const
1771 {
1772         RegionLock rlock (const_cast<Playlist*> (this));
1773
1774         /* searches all regions currently in use by the playlist */
1775
1776         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1777                 if ((*i)->id() == id) {
1778                         return *i;
1779                 }
1780         }
1781
1782         return boost::shared_ptr<Region> ();
1783 }
1784
1785 boost::shared_ptr<Region>
1786 Playlist::region_by_id (ID id)
1787 {
1788         /* searches all regions ever added to this playlist */
1789
1790         for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
1791                 if ((*i)->id() == id) {
1792                         return *i;
1793                 }
1794         }
1795         return boost::shared_ptr<Region> ();
1796 }
1797         
1798 void
1799 Playlist::dump () const
1800 {
1801         boost::shared_ptr<Region> r;
1802
1803         cerr << "Playlist \"" << _name << "\" " << endl
1804              << regions.size() << " regions "
1805              << endl;
1806
1807         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1808                 r = *i;
1809                 cerr << "  " << r->name() << " [" 
1810                      << r->start() << "+" << r->length() 
1811                      << "] at " 
1812                      << r->position()
1813                      << " on layer "
1814                      << r->layer ()
1815                      << endl;
1816         }
1817 }
1818
1819 void
1820 Playlist::set_frozen (bool yn)
1821 {
1822         _frozen = yn;
1823 }
1824
1825 void
1826 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
1827 {
1828 //      struct timeval tv;
1829 //      gettimeofday (&tv, 0);
1830         region->set_last_layer_op (++layer_op_counter);
1831 }
1832