When a track is in "stacked" mode, allow regions to be moved to different layers...
[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 Playlist::RegionList*
1424 Playlist::regions_to_read (nframes_t start, nframes_t end)
1425 {
1426         /* Caller must hold lock */
1427
1428         RegionList covering;
1429         set<nframes_t> to_check;
1430         set<boost::shared_ptr<Region> > unique;
1431         RegionList here;
1432
1433         to_check.insert (start);
1434         to_check.insert (end);
1435
1436         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1437
1438                 /* find all/any regions that span start+end */
1439
1440                 switch ((*i)->coverage (start, end)) {
1441                 case OverlapNone:
1442                         break;
1443
1444                 case OverlapInternal:
1445                         covering.push_back (*i);
1446                         break;
1447
1448                 case OverlapStart:
1449                         to_check.insert ((*i)->position());
1450                         covering.push_back (*i);
1451                         break;
1452
1453                 case OverlapEnd:
1454                         to_check.insert ((*i)->last_frame());
1455                         covering.push_back (*i);
1456                         break;
1457
1458                 case OverlapExternal:
1459                         covering.push_back (*i);
1460                         to_check.insert ((*i)->position());
1461                         to_check.insert ((*i)->last_frame());
1462                         break;
1463                 }
1464
1465                 /* don't go too far */
1466
1467                 if ((*i)->position() > end) {
1468                         break;
1469                 }
1470         }
1471
1472         RegionList* rlist = new RegionList;
1473
1474         /* find all the regions that cover each position .... */
1475
1476         if (covering.size() == 1) {
1477
1478                 rlist->push_back (covering.front());
1479                 
1480         } else {
1481         
1482                 for (set<nframes_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
1483                         
1484                         here.clear ();
1485                         
1486                         for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
1487                         
1488                                 if ((*x)->covers (*t)) {
1489                                         here.push_back (*x);
1490                                 }
1491                         }
1492                         
1493                         RegionSortByLayer cmp;
1494                         here.sort (cmp);
1495                         
1496                         /* ... and get the top/transparent regions at "here" */
1497                         
1498                         for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
1499                                 
1500                                 unique.insert (*c);
1501                                 
1502                                 if ((*c)->opaque()) {
1503                                         
1504                                         /* the other regions at this position are hidden by this one */
1505                                         
1506                                         break;
1507                                 }
1508                         }
1509                 }
1510                 
1511                 for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
1512                         rlist->push_back (*s);
1513                 }
1514
1515                 if (rlist->size() > 1) {
1516                         /* now sort by time order */
1517                         
1518                         RegionSortByPosition cmp;
1519                         rlist->sort (cmp);
1520                 }
1521         }
1522
1523         return rlist;
1524 }
1525
1526 Playlist::RegionList *
1527 Playlist::find_regions_at (nframes_t frame)
1528 {
1529         /* Caller must hold lock */
1530
1531         RegionList *rlist = new RegionList;
1532
1533         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1534                 if ((*i)->covers (frame)) {
1535                         rlist->push_back (*i);
1536                 }
1537         }
1538
1539         return rlist;
1540 }
1541
1542 Playlist::RegionList *
1543 Playlist::regions_touched (nframes_t start, nframes_t end)
1544 {
1545         RegionLock rlock (this);
1546         RegionList *rlist = new RegionList;
1547
1548         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1549                 if ((*i)->coverage (start, end) != OverlapNone) {
1550                         rlist->push_back (*i);
1551                 }
1552         }
1553
1554         return rlist;
1555 }
1556
1557 nframes64_t
1558 Playlist::find_next_transient (nframes64_t from, int dir)
1559 {
1560         RegionLock rlock (this);
1561         AnalysisFeatureList points;
1562         AnalysisFeatureList these_points;
1563
1564         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1565                 if (dir > 0) {
1566                         if ((*i)->last_frame() < from) {
1567                                 continue;
1568                         }
1569                 } else {
1570                         if ((*i)->first_frame() > from) {
1571                                 continue;
1572                         }
1573                 }
1574
1575                 (*i)->get_transients (these_points);
1576
1577                 /* add first frame, just, err, because */
1578                 
1579                 these_points.push_back ((*i)->first_frame());
1580                 
1581                 points.insert (points.end(), these_points.begin(), these_points.end());
1582                 these_points.clear ();
1583         }
1584         
1585         if (points.empty()) {
1586                 return -1;
1587         }
1588
1589         TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
1590         bool reached = false;
1591         
1592         if (dir > 0) {
1593                 for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
1594                         if ((*x) >= from) {
1595                                 reached = true;
1596                         }
1597                         
1598                         if (reached && (*x) > from) {
1599                                 return *x;
1600                         }
1601                 }
1602         } else {
1603                 for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
1604                         if ((*x) <= from) {
1605                                 reached = true;
1606                         }
1607                         
1608                         if (reached && (*x) < from) {
1609                                 return *x;
1610                         }
1611                 }
1612         }
1613
1614         return -1;
1615 }
1616
1617 boost::shared_ptr<Region>
1618 Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
1619 {
1620         RegionLock rlock (this);
1621         boost::shared_ptr<Region> ret;
1622         nframes_t closest = max_frames;
1623
1624         bool end_iter = false;
1625
1626         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1627
1628                 if(end_iter) break;
1629
1630                 nframes_t distance;
1631                 boost::shared_ptr<Region> r = (*i);
1632                 nframes_t pos = 0;
1633
1634                 switch (point) {
1635                 case Start:
1636                         pos = r->first_frame ();
1637                         break;
1638                 case End:
1639                         pos = r->last_frame ();
1640                         break;
1641                 case SyncPoint:
1642                         pos = r->sync_position ();
1643                         // r->adjust_to_sync (r->first_frame());
1644                         break;
1645                 }
1646
1647                 switch (dir) {
1648                 case 1: /* forwards */
1649
1650                         if (pos > frame) {
1651                                 if ((distance = pos - frame) < closest) {
1652                                         closest = distance;
1653                                         ret = r;
1654                                         end_iter = true;
1655                                 }
1656                         }
1657
1658                         break;
1659
1660                 default: /* backwards */
1661                         
1662                         if (pos < frame) {
1663                                 if ((distance = frame - pos) < closest) {
1664                                         closest = distance;
1665                                         ret = r;
1666                                 }
1667                         }
1668                         else {
1669                                 end_iter = true;
1670                         }
1671
1672                         break;
1673                 }
1674         }
1675
1676         return ret;
1677 }
1678
1679 nframes64_t
1680 Playlist::find_next_region_boundary (nframes64_t frame, int dir)
1681 {
1682         RegionLock rlock (this);
1683
1684         nframes64_t closest = max_frames;
1685         nframes64_t ret = -1;
1686
1687         if (dir > 0) {
1688
1689                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1690
1691                         boost::shared_ptr<Region> r = (*i);
1692                         nframes64_t distance;
1693                         
1694                         if (r->first_frame() > frame) {
1695
1696                                 distance = r->first_frame() - frame;
1697                                 
1698                                 if (distance < closest) {
1699                                         ret = r->first_frame();
1700                                         closest = distance;
1701                                 }
1702                         }
1703
1704                         if (r->last_frame () > frame) {
1705                                 
1706                                 distance = r->last_frame () - frame;
1707                                 
1708                                 if (distance < closest) {
1709                                         ret = r->last_frame ();
1710                                         closest = distance;
1711                                 }
1712                         }
1713                 }
1714
1715         } else {
1716
1717                 for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
1718                         
1719                         boost::shared_ptr<Region> r = (*i);
1720                         nframes64_t distance;
1721
1722                         if (r->last_frame() < frame) {
1723
1724                                 distance = frame - r->last_frame();
1725                                 
1726                                 if (distance < closest) {
1727                                         ret = r->last_frame();
1728                                         closest = distance;
1729                                 }
1730                         }
1731
1732                         if (r->first_frame() < frame) {
1733                                 
1734                                 distance = frame - r->first_frame();
1735
1736                                 if (distance < closest) {
1737                                         ret = r->first_frame();
1738                                         closest = distance;
1739                                 }
1740                         }
1741                 }
1742         }
1743
1744         return ret;
1745 }
1746
1747 /***********************************************************************/
1748
1749
1750
1751
1752 void
1753 Playlist::mark_session_dirty ()
1754 {
1755         if (!in_set_state && !holding_state ()) {
1756                 _session.set_dirty();
1757         }
1758 }
1759
1760 int
1761 Playlist::set_state (const XMLNode& node)
1762 {
1763         XMLNode *child;
1764         XMLNodeList nlist;
1765         XMLNodeConstIterator niter;
1766         XMLPropertyList plist;
1767         XMLPropertyConstIterator piter;
1768         XMLProperty *prop;
1769         boost::shared_ptr<Region> region;
1770         string region_name;
1771
1772         in_set_state++;
1773
1774         if (node.name() != "Playlist") {
1775                 in_set_state--;
1776                 return -1;
1777         }
1778
1779         freeze ();
1780
1781         plist = node.properties();
1782
1783         for (piter = plist.begin(); piter != plist.end(); ++piter) {
1784
1785                 prop = *piter;
1786                 
1787                 if (prop->name() == X_("name")) {
1788                         _name = prop->value();
1789                 } else if (prop->name() == X_("orig_diskstream_id")) {
1790                         _orig_diskstream_id = prop->value ();
1791                 } else if (prop->name() == X_("frozen")) {
1792                         _frozen = (prop->value() == X_("yes"));
1793                 }
1794         }
1795
1796         clear (false);
1797         
1798         nlist = node.children();
1799
1800         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1801
1802                 child = *niter;
1803                 
1804                 if (child->name() == "Region") {
1805
1806                         if ((prop = child->property ("id")) == 0) {
1807                                 error << _("region state node has no ID, ignored") << endmsg;
1808                                 continue;
1809                         }
1810                         
1811                         ID id = prop->value ();
1812                         
1813                         if ((region = region_by_id (id))) {
1814
1815                                 Change what_changed = Change (0);
1816
1817                                 if (region->set_live_state (*child, what_changed, true)) {
1818                                         error << _("Playlist: cannot reset region state from XML") << endmsg;
1819                                         continue;
1820                                 }
1821
1822                         } else if ((region = RegionFactory::create (_session, *child, true)) == 0) {
1823                                 error << _("Playlist: cannot create region from XML") << endmsg;
1824                                 continue;
1825                         }
1826
1827                         add_region (region, region->position(), 1.0);
1828
1829                         // So that layer_op ordering doesn't get screwed up
1830                         region->set_last_layer_op( region->layer());
1831
1832                 }                       
1833         }
1834         
1835         notify_modified ();
1836
1837         thaw ();
1838
1839         /* update dependents, which was not done during add_region_internal 
1840            due to in_set_state being true 
1841         */
1842
1843         for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1844                 check_dependents (*r, false);
1845         }
1846
1847         in_set_state--;
1848         first_set_state = false;
1849         return 0;
1850 }
1851
1852 XMLNode&
1853 Playlist::get_state()
1854 {
1855         return state (true);
1856 }
1857
1858 XMLNode&
1859 Playlist::get_template()
1860 {
1861         return state (false);
1862 }
1863
1864 /** @param full_state true to include regions in the returned state, otherwise false.
1865  */
1866 XMLNode&
1867 Playlist::state (bool full_state)
1868 {
1869         XMLNode *node = new XMLNode (X_("Playlist"));
1870         char buf[64];
1871         
1872         node->add_property (X_("name"), _name);
1873         node->add_property (X_("type"), _type.to_string());
1874
1875         _orig_diskstream_id.print (buf, sizeof (buf));
1876         node->add_property (X_("orig_diskstream_id"), buf);
1877         node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1878
1879         if (full_state) {
1880                 RegionLock rlock (this, false);
1881                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1882                         node->add_child_nocopy ((*i)->get_state());
1883                 }
1884         }
1885
1886         if (_extra_xml) {
1887                 node->add_child_copy (*_extra_xml);
1888         }
1889
1890         return *node;
1891 }
1892
1893 bool
1894 Playlist::empty() const
1895 {
1896         RegionLock rlock (const_cast<Playlist *>(this), false);
1897         return regions.empty();
1898 }
1899
1900 uint32_t
1901 Playlist::n_regions() const
1902 {
1903         RegionLock rlock (const_cast<Playlist *>(this), false);
1904         return regions.size();
1905 }
1906
1907 nframes_t
1908 Playlist::get_maximum_extent () const
1909 {
1910         RegionLock rlock (const_cast<Playlist *>(this), false);
1911         return _get_maximum_extent ();
1912 }
1913
1914 ARDOUR::nframes_t
1915 Playlist::_get_maximum_extent () const
1916 {
1917         RegionList::const_iterator i;
1918         nframes_t max_extent = 0;
1919         nframes_t end = 0;
1920
1921         for (i = regions.begin(); i != regions.end(); ++i) {
1922                 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1923                         max_extent = end;
1924                 }
1925         }
1926
1927         return max_extent;
1928 }
1929
1930 string 
1931 Playlist::bump_name (string name, Session &session)
1932 {
1933         string newname = name;
1934
1935         do {
1936                 newname = bump_name_once (newname);
1937         } while (session.playlist_by_name (newname)!=NULL);
1938
1939         return newname;
1940 }
1941
1942
1943 layer_t
1944 Playlist::top_layer() const
1945 {
1946         RegionLock rlock (const_cast<Playlist *> (this));       
1947         layer_t top = 0;
1948
1949         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1950                 top = max (top, (*i)->layer());
1951         }
1952         return top;
1953 }
1954
1955 void
1956 Playlist::set_edit_mode (EditMode mode)
1957 {
1958         _edit_mode = mode;
1959 }
1960
1961 /********************
1962  * Region Layering
1963  ********************/
1964
1965 void
1966 Playlist::relayer ()
1967 {
1968         /* don't send multiple Modified notifications
1969            when multiple regions are relayered.
1970         */
1971  
1972         freeze ();
1973
1974         /* Build up a new list of regions on each layer, stored in a set of lists
1975            each of which represent some period of time on some layer.  The idea
1976            is to avoid having to search the entire region list to establish whether
1977            each region overlaps another */
1978
1979         /* how many pieces to divide this playlist's time up into */
1980         int const divisions = 512;
1981
1982         /* find the start and end positions of the regions on this playlist */
1983         nframes_t start = UINT_MAX;
1984         nframes_t end = 0;
1985         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1986                 start = min (start, (*i)->position());
1987                 end = max (end, (*i)->position() + (*i)->length());
1988         }
1989
1990         /* hence the size of each time division */
1991         double const division_size = (end - start) / divisions;
1992
1993         vector<vector<RegionList> > layers;
1994         layers.push_back (vector<RegionList> (divisions));
1995
1996         /* we want to go through regions from desired lowest to desired highest layer,
1997            which depends on the layer model
1998         */
1999
2000         RegionList copy = regions;
2001
2002         /* sort according to the model and the layering mode that we're in */
2003
2004         if (_explicit_relayering) {
2005
2006                 copy.sort (RegionSortByLayerWithPending ());
2007
2008         } else if (_session.config.get_layer_model() == MoveAddHigher || _session.config.get_layer_model() == AddHigher) {
2009
2010                 copy.sort (RegionSortByLastLayerOp ());
2011                 
2012         }
2013
2014         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
2015
2016                 /* reset the pending explicit relayer flag for every region, now that we're relayering */
2017                 (*i)->set_pending_explicit_relayer (false);
2018
2019                 /* find the time divisions that this region covers */
2020                 int const start_division = floor ( ((*i)->position() - start) / division_size);
2021                 int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
2022                 if (end_division == divisions) {
2023                         end_division--;
2024                 }
2025
2026                 /* find the lowest layer that this region can go on */
2027                 size_t j = layers.size();
2028                 while (j > 0) {
2029                         /* try layer j - 1; it can go on if it overlaps no other region
2030                            that is already on that layer
2031                         */
2032
2033                         bool overlap = false;
2034                         for (int k = start_division; k <= end_division; ++k) {
2035                                 RegionList::iterator l = layers[j-1][k].begin ();
2036                                 while (l != layers[j-1][k].end()) {
2037                                         if ((*l)->overlap_equivalent (*i)) {
2038                                                 overlap = true;
2039                                                 break;
2040                                         }
2041                                         l++;
2042                                 }
2043
2044                                 if (overlap) {
2045                                         break;
2046                                 }
2047                         }
2048
2049                         if (overlap) {
2050                                 /* overlap, so we must use layer j */
2051                                 break;
2052                         }
2053                         
2054                         --j;
2055                 }
2056
2057                 if (j == layers.size()) {
2058                         /* we need a new layer for this region */
2059                         layers.push_back (vector<RegionList> (divisions));
2060                 }
2061
2062                 /* put a reference to this region in each of the divisions that it exists in */
2063                 for (int k = start_division; k <= end_division; ++k) {
2064                         layers[j][k].push_back (*i);
2065                 }
2066
2067                 (*i)->set_layer (j);
2068         }
2069
2070         /* sending Modified means that various kinds of layering
2071            models operate correctly at the GUI
2072            level. slightly inefficient, but only slightly.
2073
2074            We force a Modified signal here in case no layers actually
2075            changed.
2076         */
2077
2078         notify_modified ();
2079
2080         thaw ();
2081 }
2082
2083 /* XXX these layer functions are all deprecated */
2084
2085 void
2086 Playlist::raise_region (boost::shared_ptr<Region> region)
2087 {
2088         uint32_t rsz = regions.size();
2089         layer_t target = region->layer() + 1U;
2090
2091         if (target >= rsz) {
2092                 /* its already at the effective top */
2093                 return;
2094         }
2095
2096         move_region_to_layer (target, region, 1);
2097 }
2098
2099 void
2100 Playlist::lower_region (boost::shared_ptr<Region> region)
2101 {
2102         if (region->layer() == 0) {
2103                 /* its already at the bottom */
2104                 return;
2105         }
2106
2107         layer_t target = region->layer() - 1U;
2108
2109         move_region_to_layer (target, region, -1);
2110 }
2111
2112 void
2113 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
2114 {
2115         /* does nothing useful if layering mode is later=higher */
2116         if ((_session.config.get_layer_model() == MoveAddHigher) ||
2117             (_session.config.get_layer_model() == AddHigher)) {
2118                 timestamp_layer_op (region);
2119                 relayer ();
2120         }
2121 }
2122
2123 void
2124 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
2125 {
2126         /* does nothing useful if layering mode is later=higher */
2127         if ((_session.config.get_layer_model() == MoveAddHigher) ||
2128             (_session.config.get_layer_model() == AddHigher)) {
2129                 region->set_last_layer_op (0);
2130                 relayer ();
2131         }
2132 }
2133
2134 int
2135 Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
2136 {
2137         RegionList::iterator i;
2138         typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
2139         list<LayerInfo> layerinfo;
2140         layer_t dest;
2141
2142         {
2143                 RegionLock rlock (const_cast<Playlist *> (this));
2144                 
2145                 for (i = regions.begin(); i != regions.end(); ++i) {
2146                         
2147                         if (region == *i) {
2148                                 continue;
2149                         }
2150
2151                         if (dir > 0) {
2152
2153                                 /* region is moving up, move all regions on intermediate layers
2154                                    down 1
2155                                 */
2156                                 
2157                                 if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
2158                                         dest = (*i)->layer() - 1;
2159                                 } else {
2160                                         /* not affected */
2161                                         continue;
2162                                 }
2163                         } else {
2164
2165                                 /* region is moving down, move all regions on intermediate layers
2166                                    up 1
2167                                 */
2168
2169                                 if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
2170                                         dest = (*i)->layer() + 1;
2171                                 } else {
2172                                         /* not affected */
2173                                         continue;
2174                                 }
2175                         }
2176
2177                         LayerInfo newpair;
2178                         
2179                         newpair.first = *i;
2180                         newpair.second = dest;
2181                         
2182                         layerinfo.push_back (newpair);
2183                 } 
2184         }
2185
2186         /* now reset the layers without holding the region lock */
2187
2188         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2189                 x->first->set_layer (x->second);
2190         }
2191
2192         region->set_layer (target_layer);
2193
2194 #if 0
2195         /* now check all dependents */
2196
2197         for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
2198                 check_dependents (x->first, false);
2199         }
2200         
2201         check_dependents (region, false);
2202 #endif
2203         
2204         return 0;
2205 }
2206
2207 void
2208 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
2209 {
2210         RegionList::iterator i;
2211         nframes_t new_pos;
2212         bool moved = false;
2213
2214         _nudging = true;
2215
2216         {
2217                 RegionLock rlock (const_cast<Playlist *> (this));
2218                 
2219                 for (i = regions.begin(); i != regions.end(); ++i) {
2220
2221                         if ((*i)->position() >= start) {
2222
2223                                 if (forwards) {
2224
2225                                         if ((*i)->last_frame() > max_frames - distance) {
2226                                                 new_pos = max_frames - (*i)->length();
2227                                         } else {
2228                                                 new_pos = (*i)->position() + distance;
2229                                         }
2230                                         
2231                                 } else {
2232                                         
2233                                         if ((*i)->position() > distance) {
2234                                                 new_pos = (*i)->position() - distance;
2235                                         } else {
2236                                                 new_pos = 0;
2237                                         }
2238                                 }
2239
2240                                 (*i)->set_position (new_pos, this);
2241                                 moved = true;
2242                         }
2243                 }
2244         }
2245
2246         if (moved) {
2247                 _nudging = false;
2248                 notify_length_changed ();
2249         }
2250
2251 }
2252
2253 boost::shared_ptr<Region>
2254 Playlist::find_region (const ID& id) const
2255 {
2256         RegionLock rlock (const_cast<Playlist*> (this));
2257
2258         /* searches all regions currently in use by the playlist */
2259
2260         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2261                 if ((*i)->id() == id) {
2262                         return *i;
2263                 }
2264         }
2265
2266         return boost::shared_ptr<Region> ();
2267 }
2268
2269 boost::shared_ptr<Region>
2270 Playlist::region_by_id (ID id)
2271 {
2272         /* searches all regions ever added to this playlist */
2273
2274         for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
2275                 if ((*i)->id() == id) {
2276                         return *i;
2277                 }
2278         }
2279         return boost::shared_ptr<Region> ();
2280 }
2281         
2282 void
2283 Playlist::dump () const
2284 {
2285         boost::shared_ptr<Region> r;
2286
2287         cerr << "Playlist \"" << _name << "\" " << endl
2288              << regions.size() << " regions "
2289              << endl;
2290
2291         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2292                 r = *i;
2293                 cerr << "  " << r->name() << " [" 
2294                      << r->start() << "+" << r->length() 
2295                      << "] at " 
2296                      << r->position()
2297                      << " on layer "
2298                      << r->layer ()
2299                      << endl;
2300         }
2301 }
2302
2303 void
2304 Playlist::set_frozen (bool yn)
2305 {
2306         _frozen = yn;
2307 }
2308
2309 void
2310 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
2311 {
2312 //      struct timeval tv;
2313 //      gettimeofday (&tv, 0);
2314         region->set_last_layer_op (++layer_op_counter);
2315 }
2316
2317
2318 void
2319 Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
2320 {
2321         bool moved = false;
2322         nframes_t new_pos;
2323
2324         if (region->locked()) {
2325                 return;
2326         }
2327
2328         _shuffling = true;
2329
2330         {
2331                 RegionLock rlock (const_cast<Playlist*> (this));
2332                 
2333                 
2334                 if (dir > 0) {
2335                         
2336                         RegionList::iterator next;
2337
2338                         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {       
2339                                 if ((*i) == region) {
2340                                         next = i;
2341                                         ++next;
2342
2343                                         if (next != regions.end()) {
2344
2345                                                 if ((*next)->locked()) {
2346                                                         break;
2347                                                 }
2348
2349                                                 if ((*next)->position() != region->last_frame() + 1) {
2350                                                         /* they didn't used to touch, so after shuffle,
2351                                                            just have them swap positions.
2352                                                         */
2353                                                         new_pos = (*next)->position();
2354                                                 } else {
2355                                                         /* they used to touch, so after shuffle,
2356                                                            make sure they still do. put the earlier
2357                                                            region where the later one will end after
2358                                                            it is moved.
2359                                                         */
2360                                                         new_pos = region->position() + (*next)->length();
2361                                                 }
2362
2363                                                 (*next)->set_position (region->position(), this);
2364                                                 region->set_position (new_pos, this);
2365
2366                                                 /* avoid a full sort */
2367
2368                                                 regions.erase (i); // removes the region from the list */
2369                                                 next++;
2370                                                 regions.insert (next, region); // adds it back after next
2371
2372                                                 moved = true;
2373                                         }
2374                                         break;
2375                                 }
2376                         }
2377                 } else {
2378                         
2379                         RegionList::iterator prev = regions.end();
2380                         
2381                         for (RegionList::iterator i = regions.begin(); i != regions.end(); prev = i, ++i) {     
2382                                 if ((*i) == region) {
2383
2384                                         if (prev != regions.end()) {
2385
2386                                                 if ((*prev)->locked()) {
2387                                                         break;
2388                                                 }
2389
2390                                                 if (region->position() != (*prev)->last_frame() + 1) {
2391                                                         /* they didn't used to touch, so after shuffle,
2392                                                            just have them swap positions.
2393                                                         */
2394                                                         new_pos = region->position();
2395                                                 } else {
2396                                                         /* they used to touch, so after shuffle,
2397                                                            make sure they still do. put the earlier
2398                                                            one where the later one will end after
2399                                                         */
2400                                                         new_pos = (*prev)->position() + region->length();
2401                                                 }
2402
2403                                                 region->set_position ((*prev)->position(), this);
2404                                                 (*prev)->set_position (new_pos, this);
2405                                                 
2406                                                 /* avoid a full sort */
2407
2408                                                 regions.erase (i); // remove region
2409                                                 regions.insert (prev, region); // insert region before prev
2410
2411                                                 moved = true;
2412                                         }
2413
2414                                         break;
2415                                 }
2416                         }
2417                 }
2418         }
2419
2420         _shuffling = false;
2421
2422         if (moved) {
2423
2424                 relayer ();
2425                 check_dependents (region, false);
2426                 
2427                 notify_modified();
2428         }
2429
2430 }
2431
2432 bool
2433 Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>) 
2434 {
2435         RegionLock rlock (const_cast<Playlist*> (this));
2436         
2437         if (regions.size() > 1) {
2438                 return true;
2439         }
2440
2441         return false;
2442 }
2443
2444 void
2445 Playlist::update_after_tempo_map_change ()
2446 {
2447         RegionLock rlock (const_cast<Playlist*> (this));
2448         RegionList copy (regions);
2449
2450         freeze ();
2451         
2452         for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {     
2453                 (*i)->update_position_after_tempo_map_change ();
2454         }
2455
2456         thaw ();
2457 }
2458
2459 void
2460 Playlist::foreach_region (sigc::slot<void, boost::shared_ptr<Region> > s)
2461 {
2462         RegionLock rl (this, false);
2463         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
2464                 s (*i);
2465         }
2466 }
2467
2468