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