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