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