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