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