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