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