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