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