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