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