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