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