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