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