2 Copyright (C) 2000-2003 Paul Davis
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.
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.
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.
28 #include <sigc++/bind.h>
30 #include <pbd/failed_constructor.h>
31 #include <pbd/stl_delete.h>
32 #include <pbd/xml++.h>
33 #include <pbd/stacktrace.h>
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
39 #include <ardour/playlist_factory.h>
40 #include <ardour/transient_detector.h>
45 using namespace ARDOUR
;
48 struct ShowMeTheList
{
49 ShowMeTheList (boost::shared_ptr
<Playlist
> pl
, const string
& n
) : playlist (pl
), name (n
) {}
51 cerr
<< ">>>>" << name
<< endl
; playlist
->dump(); cerr
<< "<<<<" << name
<< endl
<< endl
;
53 boost::shared_ptr
<Playlist
> playlist
;
57 struct RegionSortByLayer
{
58 bool operator() (boost::shared_ptr
<Region
> a
, boost::shared_ptr
<Region
> b
) {
59 return a
->layer() < b
->layer();
63 struct RegionSortByPosition
{
64 bool operator() (boost::shared_ptr
<Region
> a
, boost::shared_ptr
<Region
> b
) {
65 return a
->position() < b
->position();
69 struct RegionSortByLastLayerOp
{
70 bool operator() (boost::shared_ptr
<Region
> a
, boost::shared_ptr
<Region
> b
) {
71 return a
->last_layer_op() < b
->last_layer_op();
75 Playlist::Playlist (Session
& sess
, string nom
, bool hide
)
79 first_set_state
= false;
84 Playlist::Playlist (Session
& sess
, const XMLNode
& node
, bool hide
)
88 _name
= "unnamed"; /* reset by set_state */
90 /* set state called by derived class */
93 Playlist::Playlist (boost::shared_ptr
<const Playlist
> other
, string namestr
, bool hide
)
94 : _name (namestr
), _session (other
->_session
), _orig_diskstream_id(other
->_orig_diskstream_id
)
99 other
->copy_regions (tmp
);
103 for (list
<boost::shared_ptr
<Region
> >::iterator x
= tmp
.begin(); x
!= tmp
.end(); ++x
) {
104 add_region_internal( (*x
), (*x
)->position());
109 _splicing
= other
->_splicing
;
110 _nudging
= other
->_nudging
;
111 _edit_mode
= other
->_edit_mode
;
114 first_set_state
= false;
116 in_partition
= false;
118 _read_data_count
= 0;
119 _frozen
= other
->_frozen
;
121 layer_op_counter
= other
->layer_op_counter
;
122 freeze_length
= other
->freeze_length
;
125 Playlist::Playlist (boost::shared_ptr
<const Playlist
> other
, nframes_t start
, nframes_t cnt
, string str
, bool hide
)
126 : _name (str
), _session (other
->_session
), _orig_diskstream_id(other
->_orig_diskstream_id
)
128 RegionLock
rlock2 (const_cast<Playlist
*> (other
.get()));
130 nframes_t end
= start
+ cnt
- 1;
136 for (RegionList::const_iterator i
= other
->regions
.begin(); i
!= other
->regions
.end(); i
++) {
138 boost::shared_ptr
<Region
> region
;
139 boost::shared_ptr
<Region
> new_region
;
140 nframes_t offset
= 0;
141 nframes_t position
= 0;
148 overlap
= region
->coverage (start
, end
);
154 case OverlapInternal
:
155 offset
= start
- region
->position();
162 position
= region
->position() - start
;
163 len
= end
- region
->position();
167 offset
= start
- region
->position();
169 len
= region
->length() - offset
;
172 case OverlapExternal
:
174 position
= region
->position() - start
;
175 len
= region
->length();
179 _session
.region_name (new_name
, region
->name(), false);
181 new_region
= RegionFactory::RegionFactory::create (region
, offset
, len
, new_name
, region
->layer(), region
->flags());
183 add_region_internal (new_region
, position
);
187 first_set_state
= false;
189 /* this constructor does NOT notify others (session) */
196 InUse (true); /* EMIT SIGNAL */
207 InUse (false); /* EMIT SIGNAL */
212 Playlist::copy_regions (RegionList
& newlist
) const
214 RegionLock
rlock (const_cast<Playlist
*> (this));
216 for (RegionList::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
217 newlist
.push_back (RegionFactory::RegionFactory::create (*i
));
222 Playlist::init (bool hide
)
224 g_atomic_int_set (&block_notifications
, 0);
225 g_atomic_int_set (&ignore_state_changes
, 0);
226 pending_modified
= false;
227 pending_length
= false;
228 first_set_state
= true;
235 _edit_mode
= Config
->get_edit_mode();
237 in_partition
= false;
239 _read_data_count
= 0;
241 layer_op_counter
= 0;
244 Modified
.connect (mem_fun (*this, &Playlist::mark_session_dirty
));
247 Playlist::Playlist (const Playlist
& pl
)
248 : _session (pl
._session
)
250 fatal
<< _("playlist const copy constructor called") << endmsg
;
253 Playlist::Playlist (Playlist
& pl
)
254 : _session (pl
._session
)
256 fatal
<< _("playlist non-const copy constructor called") << endmsg
;
259 Playlist::~Playlist ()
262 RegionLock
rl (this);
264 for (set
<boost::shared_ptr
<Region
> >::iterator i
= all_regions
.begin(); i
!= all_regions
.end(); ++i
) {
265 (*i
)->set_playlist (boost::shared_ptr
<Playlist
>());
269 /* GoingAway must be emitted by derived classes */
273 Playlist::set_name (string str
)
275 /* in a typical situation, a playlist is being used
276 by one diskstream and also is referenced by the
277 Session. if there are more references than that,
278 then don't change the name.
291 while (_session
.playlist_by_name(name
) != 0) {
292 name
= bump_name_once(name
);
296 NameChanged(); /* EMIT SIGNAL */
299 /***********************************************************************
300 CHANGE NOTIFICATION HANDLING
302 Notifications must be delayed till the region_lock is released. This
303 is necessary because handlers for the signals may need to acquire
304 the lock (e.g. to read from the playlist).
305 ***********************************************************************/
310 delay_notifications ();
311 g_atomic_int_inc (&ignore_state_changes
);
317 g_atomic_int_dec_and_test (&ignore_state_changes
);
318 release_notifications ();
323 Playlist::delay_notifications ()
325 g_atomic_int_inc (&block_notifications
);
326 freeze_length
= _get_maximum_extent();
330 Playlist::release_notifications ()
332 if (g_atomic_int_dec_and_test (&block_notifications
)) {
333 flush_notifications ();
338 Playlist::notify_modified ()
340 if (holding_state ()) {
341 pending_modified
= true;
343 pending_modified
= false;
344 Modified(); /* EMIT SIGNAL */
349 Playlist::notify_region_removed (boost::shared_ptr
<Region
> r
)
351 if (holding_state ()) {
352 pending_removes
.insert (r
);
353 pending_modified
= true;
354 pending_length
= true;
356 /* this might not be true, but we have to act
357 as though it could be.
359 LengthChanged (); /* EMIT SIGNAL */
360 Modified (); /* EMIT SIGNAL */
365 Playlist::notify_region_added (boost::shared_ptr
<Region
> r
)
367 /* the length change might not be true, but we have to act
368 as though it could be.
371 if (holding_state()) {
372 pending_adds
.insert (r
);
373 pending_modified
= true;
374 pending_length
= true;
376 LengthChanged (); /* EMIT SIGNAL */
377 Modified (); /* EMIT SIGNAL */
382 Playlist::notify_length_changed ()
384 if (holding_state ()) {
385 pending_length
= true;
387 LengthChanged(); /* EMIT SIGNAL */
388 Modified (); /* EMIT SIGNAL */
393 Playlist::flush_notifications ()
395 set
<boost::shared_ptr
<Region
> > dependent_checks_needed
;
396 set
<boost::shared_ptr
<Region
> >::iterator s
;
405 /* we have no idea what order the regions ended up in pending
406 bounds (it could be based on selection order, for example).
407 so, to preserve layering in the "most recently moved is higher"
408 model, sort them by existing layer, then timestamp them.
411 // RegionSortByLayer cmp;
412 // pending_bounds.sort (cmp);
414 for (RegionList::iterator r
= pending_bounds
.begin(); r
!= pending_bounds
.end(); ++r
) {
415 if (Config
->get_layer_model() == MoveAddHigher
) {
416 timestamp_layer_op (*r
);
418 pending_length
= true;
419 dependent_checks_needed
.insert (*r
);
423 for (s
= pending_adds
.begin(); s
!= pending_adds
.end(); ++s
) {
424 dependent_checks_needed
.insert (*s
);
428 for (s
= pending_removes
.begin(); s
!= pending_removes
.end(); ++s
) {
429 remove_dependents (*s
);
433 if ((freeze_length
!= _get_maximum_extent()) || pending_length
) {
435 LengthChanged(); /* EMIT SIGNAL */
439 if (n
|| pending_modified
) {
443 pending_modified
= false;
444 Modified (); /* EMIT SIGNAL */
447 for (s
= dependent_checks_needed
.begin(); s
!= dependent_checks_needed
.end(); ++s
) {
448 check_dependents (*s
, false);
451 pending_adds
.clear ();
452 pending_removes
.clear ();
453 pending_bounds
.clear ();
458 /*************************************************************
460 *************************************************************/
463 Playlist::add_region (boost::shared_ptr
<Region
> region
, nframes_t position
, float times
)
465 RegionLock
rlock (this);
467 times
= fabs (times
);
469 int itimes
= (int) floor (times
);
471 nframes_t pos
= position
;
474 add_region_internal (region
, pos
);
475 pos
+= region
->length();
480 /* note that itimes can be zero if we being asked to just
481 insert a single fraction of the region.
484 for (int i
= 0; i
< itimes
; ++i
) {
485 boost::shared_ptr
<Region
> copy
= RegionFactory::create (region
);
486 add_region_internal (copy
, pos
);
487 pos
+= region
->length();
490 nframes_t length
= 0;
492 if (floor (times
) != times
) {
493 length
= (nframes_t
) floor (region
->length() * (times
- floor (times
)));
495 _session
.region_name (name
, region
->name(), false);
496 boost::shared_ptr
<Region
> sub
= RegionFactory::create (region
, 0, length
, name
, region
->layer(), region
->flags());
497 add_region_internal (sub
, pos
);
501 possibly_splice_unlocked (position
, (pos
+ length
) - position
, boost::shared_ptr
<Region
>());
505 Playlist::set_region_ownership ()
507 RegionLock
rl (this);
508 RegionList::iterator i
;
509 boost::weak_ptr
<Playlist
> pl (shared_from_this());
511 for (i
= regions
.begin(); i
!= regions
.end(); ++i
) {
512 (*i
)->set_playlist (pl
);
517 Playlist::add_region_internal (boost::shared_ptr
<Region
> region
, nframes_t position
)
519 RegionSortByPosition cmp
;
520 nframes_t old_length
= 0;
522 if (!holding_state()) {
523 old_length
= _get_maximum_extent();
526 if (!first_set_state
) {
527 boost::shared_ptr
<Playlist
> foo (shared_from_this());
528 region
->set_playlist (boost::weak_ptr
<Playlist
>(foo
));
531 region
->set_position (position
, this);
533 timestamp_layer_op (region
);
535 regions
.insert (upper_bound (regions
.begin(), regions
.end(), region
, cmp
), region
);
536 all_regions
.insert (region
);
538 possibly_splice_unlocked (position
, region
->length(), region
);
540 if (!holding_state () && !in_set_state
) {
541 /* layers get assigned from XML state */
545 /* we need to notify the existence of new region before checking dependents. Ick. */
547 notify_region_added (region
);
549 if (!holding_state ()) {
550 check_dependents (region
, false);
551 if (old_length
!= _get_maximum_extent()) {
552 notify_length_changed ();
556 region
->StateChanged
.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy
),
557 boost::weak_ptr
<Region
> (region
)));
561 Playlist::replace_region (boost::shared_ptr
<Region
> old
, boost::shared_ptr
<Region
> newr
, nframes_t pos
)
563 RegionLock
rlock (this);
565 bool old_sp
= _splicing
;
568 remove_region_internal (old
);
569 add_region_internal (newr
, pos
);
573 possibly_splice_unlocked (pos
, (nframes64_t
) old
->length() - (nframes64_t
) newr
->length());
577 Playlist::remove_region (boost::shared_ptr
<Region
> region
)
579 RegionLock
rlock (this);
580 remove_region_internal (region
);
584 Playlist::remove_region_internal (boost::shared_ptr
<Region
> region
)
586 RegionList::iterator i
;
587 nframes_t old_length
= 0;
589 if (!holding_state()) {
590 old_length
= _get_maximum_extent();
595 region
->set_playlist (boost::weak_ptr
<Playlist
>());
598 for (i
= regions
.begin(); i
!= regions
.end(); ++i
) {
601 nframes_t pos
= (*i
)->position();
602 nframes64_t distance
= (*i
)->length();
606 possibly_splice_unlocked (pos
, -distance
);
608 if (!holding_state ()) {
610 remove_dependents (region
);
612 if (old_length
!= _get_maximum_extent()) {
613 notify_length_changed ();
617 notify_region_removed (region
);
628 Playlist::get_equivalent_regions (boost::shared_ptr
<Region
> other
, vector
<boost::shared_ptr
<Region
> >& results
)
630 if (Config
->get_use_overlap_equivalency()) {
631 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
632 if ((*i
)->overlap_equivalent (other
)) {
633 results
.push_back ((*i
));
637 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
638 if ((*i
)->equivalent (other
)) {
639 results
.push_back ((*i
));
646 Playlist::get_region_list_equivalent_regions (boost::shared_ptr
<Region
> other
, vector
<boost::shared_ptr
<Region
> >& results
)
648 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
650 if ((*i
) && (*i
)->region_list_equivalent (other
)) {
651 results
.push_back (*i
);
657 Playlist::partition (nframes_t start
, nframes_t end
, bool just_top_level
)
661 partition_internal (start
, end
, false, thawlist
);
663 for (RegionList::iterator i
= thawlist
.begin(); i
!= thawlist
.end(); ++i
) {
664 (*i
)->thaw ("separation");
669 Playlist::partition_internal (nframes_t start
, nframes_t end
, bool cutting
, RegionList
& thawlist
)
671 RegionList new_regions
;
674 RegionLock
rlock (this);
675 boost::shared_ptr
<Region
> region
;
676 boost::shared_ptr
<Region
> current
;
678 RegionList::iterator tmp
;
680 nframes_t pos1
, pos2
, pos3
, pos4
;
684 /* need to work from a copy, because otherwise the regions we add during the process
685 get operated on as well.
688 RegionList copy
= regions
;
690 for (RegionList::iterator i
= copy
.begin(); i
!= copy
.end(); i
= tmp
) {
697 if (current
->first_frame() >= start
&& current
->last_frame() < end
) {
699 remove_region_internal (current
);
704 /* coverage will return OverlapStart if the start coincides
705 with the end point. we do not partition such a region,
706 so catch this special case.
709 if (current
->first_frame() >= end
) {
713 if ((overlap
= current
->coverage (start
, end
)) == OverlapNone
) {
717 pos1
= current
->position();
720 pos4
= current
->last_frame();
722 if (overlap
== OverlapInternal
) {
724 /* split: we need 3 new regions, the front, middle and end.
725 cut: we need 2 regions, the front and end.
730 ---------------*************************------------
733 ---------------*****++++++++++++++++====------------
735 ---------------*****----------------====------------
741 /* "middle" ++++++ */
743 _session
.region_name (new_name
, current
->name(), false);
744 region
= RegionFactory::create (current
, pos2
- pos1
, pos3
- pos2
, new_name
,
745 regions
.size(), Region::Flag(current
->flags()|Region::Automatic
|Region::LeftOfSplit
|Region::RightOfSplit
));
746 add_region_internal (region
, start
);
747 new_regions
.push_back (region
);
752 _session
.region_name (new_name
, current
->name(), false);
753 region
= RegionFactory::create (current
, pos3
- pos1
, pos4
- pos3
, new_name
,
754 regions
.size(), Region::Flag(current
->flags()|Region::Automatic
|Region::RightOfSplit
));
756 add_region_internal (region
, end
);
757 new_regions
.push_back (region
);
762 thawlist
.push_back (current
);
763 current
->trim_end (pos2
, this);
765 } else if (overlap
== OverlapEnd
) {
769 ---------------*************************------------
772 ---------------**************+++++++++++------------
774 ---------------**************-----------------------
781 _session
.region_name (new_name
, current
->name(), false);
782 region
= RegionFactory::create (current
, pos2
- pos1
, pos4
- pos2
, new_name
, (layer_t
) regions
.size(),
783 Region::Flag(current
->flags()|Region::Automatic
|Region::LeftOfSplit
));
784 add_region_internal (region
, start
);
785 new_regions
.push_back (region
);
791 thawlist
.push_back (current
);
792 current
->trim_end (pos2
, this);
794 } else if (overlap
== OverlapStart
) {
796 /* split: we need 2 regions: the front and the end.
797 cut: just trim current to skip the cut area
802 ---------------*************************------------
806 ---------------****+++++++++++++++++++++------------
808 -------------------*********************------------
815 _session
.region_name (new_name
, current
->name(), false);
816 region
= RegionFactory::create (current
, 0, pos3
- pos1
, new_name
,
817 regions
.size(), Region::Flag(current
->flags()|Region::Automatic
|Region::RightOfSplit
));
818 add_region_internal (region
, pos1
);
819 new_regions
.push_back (region
);
825 thawlist
.push_back (current
);
826 current
->trim_front (pos3
, this);
828 } else if (overlap
== OverlapExternal
) {
830 /* split: no split required.
831 cut: remove the region.
836 ---------------*************************------------
840 ---------------*************************------------
842 ----------------------------------------------------
847 remove_region_internal (current
);
849 new_regions
.push_back (current
);
853 in_partition
= false;
856 for (RegionList::iterator i
= new_regions
.begin(); i
!= new_regions
.end(); ++i
) {
857 check_dependents (*i
, false);
861 boost::shared_ptr
<Playlist
>
862 Playlist::cut_copy (boost::shared_ptr
<Playlist
> (Playlist::*pmf
)(nframes_t
, nframes_t
,bool), list
<AudioRange
>& ranges
, bool result_is_hidden
)
864 boost::shared_ptr
<Playlist
> ret
;
865 boost::shared_ptr
<Playlist
> pl
;
868 if (ranges
.empty()) {
869 return boost::shared_ptr
<Playlist
>();
872 start
= ranges
.front().start
;
874 for (list
<AudioRange
>::iterator i
= ranges
.begin(); i
!= ranges
.end(); ++i
) {
876 pl
= (this->*pmf
)((*i
).start
, (*i
).length(), result_is_hidden
);
878 if (i
== ranges
.begin()) {
882 /* paste the next section into the nascent playlist,
883 offset to reflect the start of the first range we
887 ret
->paste (pl
, (*i
).start
- start
, 1.0f
);
894 boost::shared_ptr
<Playlist
>
895 Playlist::cut (list
<AudioRange
>& ranges
, bool result_is_hidden
)
897 boost::shared_ptr
<Playlist
> (Playlist::*pmf
)(nframes_t
,nframes_t
,bool) = &Playlist::cut
;
898 return cut_copy (pmf
, ranges
, result_is_hidden
);
901 boost::shared_ptr
<Playlist
>
902 Playlist::copy (list
<AudioRange
>& ranges
, bool result_is_hidden
)
904 boost::shared_ptr
<Playlist
> (Playlist::*pmf
)(nframes_t
,nframes_t
,bool) = &Playlist::copy
;
905 return cut_copy (pmf
, ranges
, result_is_hidden
);
908 boost::shared_ptr
<Playlist
>
909 Playlist::cut (nframes_t start
, nframes_t cnt
, bool result_is_hidden
)
911 boost::shared_ptr
<Playlist
> the_copy
;
915 snprintf (buf
, sizeof (buf
), "%" PRIu32
, ++subcnt
);
916 string new_name
= _name
;
920 if ((the_copy
= PlaylistFactory::create (shared_from_this(), start
, cnt
, new_name
, result_is_hidden
)) == 0) {
921 return boost::shared_ptr
<Playlist
>();
924 partition_internal (start
, start
+cnt
-1, true, thawlist
);
926 for (RegionList::iterator i
= thawlist
.begin(); i
!= thawlist
.end(); ++i
) {
927 (*i
)->thaw ("playlist cut");
933 boost::shared_ptr
<Playlist
>
934 Playlist::copy (nframes_t start
, nframes_t cnt
, bool result_is_hidden
)
938 snprintf (buf
, sizeof (buf
), "%" PRIu32
, ++subcnt
);
939 string new_name
= _name
;
943 cnt
= min (_get_maximum_extent() - start
, cnt
);
944 return PlaylistFactory::create (shared_from_this(), start
, cnt
, new_name
, result_is_hidden
);
948 Playlist::paste (boost::shared_ptr
<Playlist
> other
, nframes_t position
, float times
)
950 times
= fabs (times
);
951 nframes_t old_length
;
954 RegionLock
rl1 (this);
955 RegionLock
rl2 (other
.get());
957 old_length
= _get_maximum_extent();
959 int itimes
= (int) floor (times
);
960 nframes_t pos
= position
;
961 nframes_t shift
= other
->_get_maximum_extent();
962 layer_t top_layer
= regions
.size();
965 for (RegionList::iterator i
= other
->regions
.begin(); i
!= other
->regions
.end(); ++i
) {
966 boost::shared_ptr
<Region
> copy_of_region
= RegionFactory::create (*i
);
968 /* put these new regions on top of all existing ones, but preserve
969 the ordering they had in the original playlist.
972 copy_of_region
->set_layer (copy_of_region
->layer() + top_layer
);
973 add_region_internal (copy_of_region
, copy_of_region
->position() + pos
);
979 /* XXX shall we handle fractional cases at some point? */
981 if (old_length
!= _get_maximum_extent()) {
982 notify_length_changed ();
993 Playlist::duplicate (boost::shared_ptr
<Region
> region
, nframes_t position
, float times
)
995 times
= fabs (times
);
997 RegionLock
rl (this);
998 int itimes
= (int) floor (times
);
999 nframes_t pos
= position
;
1002 boost::shared_ptr
<Region
> copy
= RegionFactory::create (region
);
1003 add_region_internal (copy
, pos
);
1004 pos
+= region
->length();
1007 if (floor (times
) != times
) {
1008 nframes_t length
= (nframes_t
) floor (region
->length() * (times
- floor (times
)));
1010 _session
.region_name (name
, region
->name(), false);
1011 boost::shared_ptr
<Region
> sub
= RegionFactory::create (region
, 0, length
, name
, region
->layer(), region
->flags());
1012 add_region_internal (sub
, pos
);
1017 Playlist::shift (nframes64_t at
, nframes64_t distance
, bool move_intersected
, bool ignore_music_glue
)
1019 RegionLock
rlock (this);
1020 RegionList
copy (regions
);
1023 for (RegionList::iterator r
= copy
.begin(); r
!= copy
.end(); ++r
) {
1025 if ((*r
)->last_frame() < at
) {
1030 if (at
> (*r
)->first_frame() && at
< (*r
)->last_frame()) {
1031 /* intersected region */
1032 if (!move_intersected
) {
1037 /* do not move regions glued to music time - that
1038 has to be done separately.
1041 if (!ignore_music_glue
&& (*r
)->positional_lock_style() != Region::AudioTime
) {
1042 fixup
.push_back (*r
);
1046 (*r
)->set_position ((*r
)->position() + distance
, this);
1049 for (RegionList::iterator r
= fixup
.begin(); r
!= fixup
.end(); ++r
) {
1050 (*r
)->recompute_position_from_lock_style ();
1055 Playlist::split (nframes64_t at
)
1057 RegionLock
rlock (this);
1058 RegionList
copy (regions
);
1060 /* use a copy since this operation can modify the region list
1063 for (RegionList::iterator r
= copy
.begin(); r
!= copy
.end(); ++r
) {
1064 _split_region (*r
, at
);
1069 Playlist::split_region (boost::shared_ptr
<Region
> region
, nframes_t playlist_position
)
1071 RegionLock
rl (this);
1072 _split_region (region
, playlist_position
);
1076 Playlist::_split_region (boost::shared_ptr
<Region
> region
, nframes_t playlist_position
)
1078 if (!region
->covers (playlist_position
)) {
1082 if (region
->position() == playlist_position
||
1083 region
->last_frame() == playlist_position
) {
1087 boost::shared_ptr
<Region
> left
;
1088 boost::shared_ptr
<Region
> right
;
1094 /* split doesn't change anything about length, so don't try to splice */
1096 bool old_sp
= _splicing
;
1099 before
= playlist_position
- region
->position();
1100 after
= region
->length() - before
;
1102 _session
.region_name (before_name
, region
->name(), false);
1103 left
= RegionFactory::create (region
, 0, before
, before_name
, region
->layer(), Region::Flag (region
->flags()|Region::LeftOfSplit
));
1105 _session
.region_name (after_name
, region
->name(), false);
1106 right
= RegionFactory::create (region
, before
, after
, after_name
, region
->layer(), Region::Flag (region
->flags()|Region::RightOfSplit
));
1108 add_region_internal (left
, region
->position());
1109 add_region_internal (right
, region
->position() + before
);
1111 uint64_t orig_layer_op
= region
->last_layer_op();
1112 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1113 if ((*i
)->last_layer_op() > orig_layer_op
) {
1114 (*i
)->set_last_layer_op( (*i
)->last_layer_op() + 1 );
1118 left
->set_last_layer_op ( orig_layer_op
);
1119 right
->set_last_layer_op ( orig_layer_op
+ 1);
1123 finalize_split_region (region
, left
, right
);
1125 remove_region_internal (region
);
1131 Playlist::possibly_splice (nframes_t at
, nframes64_t distance
, boost::shared_ptr
<Region
> exclude
)
1133 if (_splicing
|| in_set_state
) {
1134 /* don't respond to splicing moves or state setting */
1138 if (_edit_mode
== Splice
) {
1139 splice_locked (at
, distance
, exclude
);
1144 Playlist::possibly_splice_unlocked (nframes_t at
, nframes64_t distance
, boost::shared_ptr
<Region
> exclude
)
1146 if (_splicing
|| in_set_state
) {
1147 /* don't respond to splicing moves or state setting */
1151 if (_edit_mode
== Splice
) {
1152 splice_unlocked (at
, distance
, exclude
);
1157 Playlist::splice_locked (nframes_t at
, nframes64_t distance
, boost::shared_ptr
<Region
> exclude
)
1160 RegionLock
rl (this);
1161 core_splice (at
, distance
, exclude
);
1166 Playlist::splice_unlocked (nframes_t at
, nframes64_t distance
, boost::shared_ptr
<Region
> exclude
)
1168 core_splice (at
, distance
, exclude
);
1172 Playlist::core_splice (nframes_t at
, nframes64_t distance
, boost::shared_ptr
<Region
> exclude
)
1176 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1178 if (exclude
&& (*i
) == exclude
) {
1182 if ((*i
)->position() >= at
) {
1183 nframes64_t new_pos
= (*i
)->position() + distance
;
1186 } else if (new_pos
>= max_frames
- (*i
)->length()) {
1187 new_pos
= max_frames
- (*i
)->length();
1190 (*i
)->set_position (new_pos
, this);
1196 notify_length_changed ();
1200 Playlist::region_bounds_changed (Change what_changed
, boost::shared_ptr
<Region
> region
)
1202 if (in_set_state
|| _splicing
|| _nudging
|| _shuffling
) {
1206 if (what_changed
& ARDOUR::PositionChanged
) {
1208 /* remove it from the list then add it back in
1209 the right place again.
1212 RegionSortByPosition cmp
;
1214 RegionList::iterator i
= find (regions
.begin(), regions
.end(), region
);
1216 if (i
== regions
.end()) {
1217 warning
<< string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1218 _name
, region
->name())
1224 regions
.insert (upper_bound (regions
.begin(), regions
.end(), region
, cmp
), region
);
1227 if (what_changed
& Change (ARDOUR::PositionChanged
|ARDOUR::LengthChanged
)) {
1229 nframes64_t delta
= 0;
1231 if (what_changed
& ARDOUR::PositionChanged
) {
1232 delta
= (nframes64_t
) region
->position() - (nframes64_t
) region
->last_position();
1235 if (what_changed
& ARDOUR::LengthChanged
) {
1236 delta
+= (nframes64_t
) region
->length() - (nframes64_t
) region
->last_length();
1240 possibly_splice (region
->last_position() + region
->last_length(), delta
, region
);
1243 if (holding_state ()) {
1244 pending_bounds
.push_back (region
);
1246 if (Config
->get_layer_model() == MoveAddHigher
) {
1247 /* it moved or changed length, so change the timestamp */
1248 timestamp_layer_op (region
);
1251 notify_length_changed ();
1253 check_dependents (region
, false);
1259 Playlist::region_changed_proxy (Change what_changed
, boost::weak_ptr
<Region
> weak_region
)
1261 boost::shared_ptr
<Region
> region (weak_region
.lock());
1268 /* this makes a virtual call to the right kind of playlist ... */
1270 region_changed (what_changed
, region
);
1274 Playlist::region_changed (Change what_changed
, boost::shared_ptr
<Region
> region
)
1276 Change our_interests
= Change (Region::MuteChanged
|Region::LayerChanged
|Region::OpacityChanged
);
1279 if (in_set_state
|| in_flush
) {
1284 if (what_changed
& BoundsChanged
) {
1285 region_bounds_changed (what_changed
, region
);
1286 save
= !(_splicing
|| _nudging
);
1289 if ((what_changed
& our_interests
) &&
1290 !(what_changed
& Change (ARDOUR::PositionChanged
|ARDOUR::LengthChanged
))) {
1291 check_dependents (region
, false);
1294 if (what_changed
& our_interests
) {
1303 Playlist::drop_regions ()
1305 RegionLock
rl (this);
1307 all_regions
.clear ();
1311 Playlist::clear (bool with_signals
)
1314 RegionLock
rl (this);
1315 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1316 pending_removes
.insert (*i
);
1328 /***********************************************************************
1330 **********************************************************************/
1332 Playlist::RegionList
*
1333 Playlist::regions_at (nframes_t frame
)
1336 RegionLock
rlock (this);
1337 return find_regions_at (frame
);
1340 boost::shared_ptr
<Region
>
1341 Playlist::top_region_at (nframes_t frame
)
1344 RegionLock
rlock (this);
1345 RegionList
*rlist
= find_regions_at (frame
);
1346 boost::shared_ptr
<Region
> region
;
1348 if (rlist
->size()) {
1349 RegionSortByLayer cmp
;
1351 region
= rlist
->back();
1358 Playlist::RegionList
*
1359 Playlist::regions_to_read (nframes_t start
, nframes_t end
)
1361 /* Caller must hold lock */
1363 RegionList covering
;
1364 set
<nframes_t
> to_check
;
1365 set
<boost::shared_ptr
<Region
> > unique
;
1368 to_check
.insert (start
);
1369 to_check
.insert (end
);
1371 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1373 /* find all/any regions that span start+end */
1375 switch ((*i
)->coverage (start
, end
)) {
1379 case OverlapInternal
:
1380 covering
.push_back (*i
);
1384 to_check
.insert ((*i
)->position());
1385 covering
.push_back (*i
);
1389 to_check
.insert ((*i
)->last_frame());
1390 covering
.push_back (*i
);
1393 case OverlapExternal
:
1394 covering
.push_back (*i
);
1395 to_check
.insert ((*i
)->position());
1396 to_check
.insert ((*i
)->last_frame());
1400 /* don't go too far */
1402 if ((*i
)->position() > end
) {
1407 RegionList
* rlist
= new RegionList
;
1409 /* find all the regions that cover each position .... */
1411 if (covering
.size() == 1) {
1413 rlist
->push_back (covering
.front());
1417 for (set
<nframes_t
>::iterator t
= to_check
.begin(); t
!= to_check
.end(); ++t
) {
1421 for (RegionList::iterator x
= covering
.begin(); x
!= covering
.end(); ++x
) {
1423 if ((*x
)->covers (*t
)) {
1424 here
.push_back (*x
);
1428 RegionSortByLayer cmp
;
1431 /* ... and get the top/transparent regions at "here" */
1433 for (RegionList::reverse_iterator c
= here
.rbegin(); c
!= here
.rend(); ++c
) {
1437 if ((*c
)->opaque()) {
1439 /* the other regions at this position are hidden by this one */
1446 for (set
<boost::shared_ptr
<Region
> >::iterator s
= unique
.begin(); s
!= unique
.end(); ++s
) {
1447 rlist
->push_back (*s
);
1450 if (rlist
->size() > 1) {
1451 /* now sort by time order */
1453 RegionSortByPosition cmp
;
1461 Playlist::RegionList
*
1462 Playlist::find_regions_at (nframes_t frame
)
1464 /* Caller must hold lock */
1466 RegionList
*rlist
= new RegionList
;
1468 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1469 if ((*i
)->covers (frame
)) {
1470 rlist
->push_back (*i
);
1477 Playlist::RegionList
*
1478 Playlist::regions_touched (nframes_t start
, nframes_t end
)
1480 RegionLock
rlock (this);
1481 RegionList
*rlist
= new RegionList
;
1483 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1484 if ((*i
)->coverage (start
, end
) != OverlapNone
) {
1485 rlist
->push_back (*i
);
1493 Playlist::find_next_transient (nframes64_t from
, int dir
)
1495 RegionLock
rlock (this);
1496 AnalysisFeatureList points
;
1497 AnalysisFeatureList these_points
;
1499 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1501 if ((*i
)->last_frame() < from
) {
1505 if ((*i
)->first_frame() > from
) {
1510 (*i
)->get_transients (these_points
);
1512 /* add first frame, just, err, because */
1514 these_points
.push_back ((*i
)->first_frame());
1516 points
.insert (points
.end(), these_points
.begin(), these_points
.end());
1517 these_points
.clear ();
1520 if (points
.empty()) {
1524 TransientDetector::cleanup_transients (points
, _session
.frame_rate(), 3.0);
1525 bool reached
= false;
1528 for (AnalysisFeatureList::iterator x
= points
.begin(); x
!= points
.end(); ++x
) {
1533 if (reached
&& (*x
) > from
) {
1538 for (AnalysisFeatureList::reverse_iterator x
= points
.rbegin(); x
!= points
.rend(); ++x
) {
1543 if (reached
&& (*x
) < from
) {
1552 boost::shared_ptr
<Region
>
1553 Playlist::find_next_region (nframes_t frame
, RegionPoint point
, int dir
)
1555 RegionLock
rlock (this);
1556 boost::shared_ptr
<Region
> ret
;
1557 nframes_t closest
= max_frames
;
1560 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1563 boost::shared_ptr
<Region
> r
= (*i
);
1568 pos
= r
->first_frame ();
1571 pos
= r
->last_frame ();
1574 pos
= r
->sync_position ();
1575 // r->adjust_to_sync (r->first_frame());
1580 case 1: /* forwards */
1583 if ((distance
= pos
- frame
) < closest
) {
1591 default: /* backwards */
1594 if ((distance
= frame
- pos
) < closest
) {
1607 Playlist::find_next_region_boundary (nframes64_t frame
, int dir
)
1609 RegionLock
rlock (this);
1611 nframes64_t closest
= max_frames
;
1612 nframes64_t ret
= -1;
1616 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1618 boost::shared_ptr
<Region
> r
= (*i
);
1619 nframes64_t distance
;
1620 nframes64_t end
= r
->position() + r
->length();
1625 if (r
->first_frame() > frame
) {
1627 distance
= r
->first_frame() - frame
;
1629 if (distance
< closest
) {
1630 ret
= r
->first_frame();
1638 distance
= end
- frame
;
1640 if (distance
< closest
) {
1654 for (RegionList::reverse_iterator i
= regions
.rbegin(); i
!= regions
.rend(); ++i
) {
1656 boost::shared_ptr
<Region
> r
= (*i
);
1657 nframes64_t distance
;
1662 if (r
->last_frame() < frame
) {
1664 distance
= frame
- r
->last_frame();
1666 if (distance
< closest
) {
1667 ret
= r
->last_frame();
1673 if (r
->first_frame() < frame
) {
1674 distance
= frame
- r
->last_frame();
1676 if (distance
< closest
) {
1677 ret
= r
->first_frame();
1692 /***********************************************************************/
1697 Playlist::mark_session_dirty ()
1699 if (!in_set_state
&& !holding_state ()) {
1700 _session
.set_dirty();
1705 Playlist::set_state (const XMLNode
& node
)
1709 XMLNodeConstIterator niter
;
1710 XMLPropertyList plist
;
1711 XMLPropertyConstIterator piter
;
1713 boost::shared_ptr
<Region
> region
;
1718 if (node
.name() != "Playlist") {
1725 plist
= node
.properties();
1727 for (piter
= plist
.begin(); piter
!= plist
.end(); ++piter
) {
1731 if (prop
->name() == X_("name")) {
1732 _name
= prop
->value();
1733 } else if (prop
->name() == X_("orig_diskstream_id")) {
1734 _orig_diskstream_id
= prop
->value ();
1735 } else if (prop
->name() == X_("frozen")) {
1736 _frozen
= (prop
->value() == X_("yes"));
1742 nlist
= node
.children();
1744 for (niter
= nlist
.begin(); niter
!= nlist
.end(); ++niter
) {
1748 if (child
->name() == "Region") {
1750 if ((prop
= child
->property ("id")) == 0) {
1751 error
<< _("region state node has no ID, ignored") << endmsg
;
1755 ID id
= prop
->value ();
1757 if ((region
= region_by_id (id
))) {
1759 Change what_changed
= Change (0);
1761 if (region
->set_live_state (*child
, what_changed
, true)) {
1762 error
<< _("Playlist: cannot reset region state from XML") << endmsg
;
1766 } else if ((region
= RegionFactory::create (_session
, *child
, true)) == 0) {
1767 error
<< _("Playlist: cannot create region from XML") << endmsg
;
1771 add_region (region
, region
->position(), 1.0);
1773 // So that layer_op ordering doesn't get screwed up
1774 region
->set_last_layer_op( region
->layer());
1783 /* update dependents, which was not done during add_region_internal
1784 due to in_set_state being true
1787 for (RegionList::iterator r
= regions
.begin(); r
!= regions
.end(); ++r
) {
1788 check_dependents (*r
, false);
1792 first_set_state
= false;
1797 Playlist::get_state()
1803 Playlist::get_template()
1805 return state(false);
1809 Playlist::state (bool full_state
)
1811 XMLNode
*node
= new XMLNode (X_("Playlist"));
1814 node
->add_property (X_("name"), _name
);
1816 _orig_diskstream_id
.print (buf
, sizeof (buf
));
1817 node
->add_property (X_("orig_diskstream_id"), buf
);
1818 node
->add_property (X_("frozen"), _frozen
? "yes" : "no");
1821 RegionLock
rlock (this, false);
1822 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1823 node
->add_child_nocopy ((*i
)->get_state());
1828 node
->add_child_copy (*_extra_xml
);
1835 Playlist::empty() const
1837 RegionLock
rlock (const_cast<Playlist
*>(this), false);
1838 return regions
.empty();
1842 Playlist::n_regions() const
1844 RegionLock
rlock (const_cast<Playlist
*>(this), false);
1845 return regions
.size();
1849 Playlist::get_maximum_extent () const
1851 RegionLock
rlock (const_cast<Playlist
*>(this), false);
1852 return _get_maximum_extent ();
1856 Playlist::_get_maximum_extent () const
1858 RegionList::const_iterator i
;
1859 nframes_t max_extent
= 0;
1862 for (i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1863 if ((end
= (*i
)->position() + (*i
)->length()) > max_extent
) {
1872 Playlist::bump_name (string name
, Session
&session
)
1874 string newname
= name
;
1877 newname
= bump_name_once (newname
);
1878 } while (session
.playlist_by_name (newname
)!=NULL
);
1885 Playlist::top_layer() const
1887 RegionLock
rlock (const_cast<Playlist
*> (this));
1890 for (RegionList::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1891 top
= max (top
, (*i
)->layer());
1897 Playlist::set_edit_mode (EditMode mode
)
1902 /********************
1904 ********************/
1907 Playlist::relayer ()
1909 RegionList::iterator i
;
1912 /* don't send multiple Modified notifications
1913 when multiple regions are relayered.
1918 if (Config
->get_layer_model() == MoveAddHigher
||
1919 Config
->get_layer_model() == AddHigher
) {
1921 RegionSortByLastLayerOp cmp
;
1922 RegionList copy
= regions
;
1926 for (i
= copy
.begin(); i
!= copy
.end(); ++i
) {
1927 (*i
)->set_layer (layer
++);
1932 /* Session::LaterHigher model */
1934 for (i
= regions
.begin(); i
!= regions
.end(); ++i
) {
1935 (*i
)->set_layer (layer
++);
1939 /* sending Modified means that various kinds of layering
1940 models operate correctly at the GUI
1941 level. slightly inefficient, but only slightly.
1943 We force a Modified signal here in case no layers actually
1952 /* XXX these layer functions are all deprecated */
1955 Playlist::raise_region (boost::shared_ptr
<Region
> region
)
1957 uint32_t rsz
= regions
.size();
1958 layer_t target
= region
->layer() + 1U;
1960 if (target
>= rsz
) {
1961 /* its already at the effective top */
1965 move_region_to_layer (target
, region
, 1);
1969 Playlist::lower_region (boost::shared_ptr
<Region
> region
)
1971 if (region
->layer() == 0) {
1972 /* its already at the bottom */
1976 layer_t target
= region
->layer() - 1U;
1978 move_region_to_layer (target
, region
, -1);
1982 Playlist::raise_region_to_top (boost::shared_ptr
<Region
> region
)
1984 /* does nothing useful if layering mode is later=higher */
1985 if ((Config
->get_layer_model() == MoveAddHigher
) ||
1986 (Config
->get_layer_model() == AddHigher
)) {
1987 timestamp_layer_op (region
);
1993 Playlist::lower_region_to_bottom (boost::shared_ptr
<Region
> region
)
1995 /* does nothing useful if layering mode is later=higher */
1996 if ((Config
->get_layer_model() == MoveAddHigher
) ||
1997 (Config
->get_layer_model() == AddHigher
)) {
1998 region
->set_last_layer_op (0);
2004 Playlist::move_region_to_layer (layer_t target_layer
, boost::shared_ptr
<Region
> region
, int dir
)
2006 RegionList::iterator i
;
2007 typedef pair
<boost::shared_ptr
<Region
>,layer_t
> LayerInfo
;
2008 list
<LayerInfo
> layerinfo
;
2012 RegionLock
rlock (const_cast<Playlist
*> (this));
2014 for (i
= regions
.begin(); i
!= regions
.end(); ++i
) {
2022 /* region is moving up, move all regions on intermediate layers
2026 if ((*i
)->layer() > region
->layer() && (*i
)->layer() <= target_layer
) {
2027 dest
= (*i
)->layer() - 1;
2034 /* region is moving down, move all regions on intermediate layers
2038 if ((*i
)->layer() < region
->layer() && (*i
)->layer() >= target_layer
) {
2039 dest
= (*i
)->layer() + 1;
2049 newpair
.second
= dest
;
2051 layerinfo
.push_back (newpair
);
2055 /* now reset the layers without holding the region lock */
2057 for (list
<LayerInfo
>::iterator x
= layerinfo
.begin(); x
!= layerinfo
.end(); ++x
) {
2058 x
->first
->set_layer (x
->second
);
2061 region
->set_layer (target_layer
);
2064 /* now check all dependents */
2066 for (list
<LayerInfo
>::iterator x
= layerinfo
.begin(); x
!= layerinfo
.end(); ++x
) {
2067 check_dependents (x
->first
, false);
2070 check_dependents (region
, false);
2077 Playlist::nudge_after (nframes_t start
, nframes_t distance
, bool forwards
)
2079 RegionList::iterator i
;
2086 RegionLock
rlock (const_cast<Playlist
*> (this));
2088 for (i
= regions
.begin(); i
!= regions
.end(); ++i
) {
2090 if ((*i
)->position() >= start
) {
2094 if ((*i
)->last_frame() > max_frames
- distance
) {
2095 new_pos
= max_frames
- (*i
)->length();
2097 new_pos
= (*i
)->position() + distance
;
2102 if ((*i
)->position() > distance
) {
2103 new_pos
= (*i
)->position() - distance
;
2109 (*i
)->set_position (new_pos
, this);
2117 notify_length_changed ();
2122 boost::shared_ptr
<Region
>
2123 Playlist::find_region (const ID
& id
) const
2125 RegionLock
rlock (const_cast<Playlist
*> (this));
2127 /* searches all regions currently in use by the playlist */
2129 for (RegionList::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
2130 if ((*i
)->id() == id
) {
2135 return boost::shared_ptr
<Region
> ();
2138 boost::shared_ptr
<Region
>
2139 Playlist::region_by_id (ID id
)
2141 /* searches all regions ever added to this playlist */
2143 for (set
<boost::shared_ptr
<Region
> >::iterator i
= all_regions
.begin(); i
!= all_regions
.end(); ++i
) {
2144 if ((*i
)->id() == id
) {
2148 return boost::shared_ptr
<Region
> ();
2152 Playlist::dump () const
2154 boost::shared_ptr
<Region
> r
;
2156 cerr
<< "Playlist \"" << _name
<< "\" " << endl
2157 << regions
.size() << " regions "
2160 for (RegionList::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
2162 cerr
<< " " << r
->name() << " ["
2163 << r
->start() << "+" << r
->length()
2173 Playlist::set_frozen (bool yn
)
2179 Playlist::timestamp_layer_op (boost::shared_ptr
<Region
> region
)
2181 // struct timeval tv;
2182 // gettimeofday (&tv, 0);
2183 region
->set_last_layer_op (++layer_op_counter
);
2188 Playlist::shuffle (boost::shared_ptr
<Region
> region
, int dir
)
2193 if (region
->locked()) {
2200 RegionLock
rlock (const_cast<Playlist
*> (this));
2205 RegionList::iterator next
;
2207 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
2208 if ((*i
) == region
) {
2212 if (next
!= regions
.end()) {
2214 if ((*next
)->locked()) {
2218 if ((*next
)->position() != region
->last_frame() + 1) {
2219 /* they didn't used to touch, so after shuffle,
2220 just have them swap positions.
2222 new_pos
= (*next
)->position();
2224 /* they used to touch, so after shuffle,
2225 make sure they still do. put the earlier
2226 region where the later one will end after
2229 new_pos
= region
->position() + (*next
)->length();
2232 (*next
)->set_position (region
->position(), this);
2233 region
->set_position (new_pos
, this);
2235 /* avoid a full sort */
2237 regions
.erase (i
); // removes the region from the list */
2239 regions
.insert (next
, region
); // adds it back after next
2248 RegionList::iterator prev
= regions
.end();
2250 for (RegionList::iterator i
= regions
.begin(); i
!= regions
.end(); prev
= i
, ++i
) {
2251 if ((*i
) == region
) {
2253 if (prev
!= regions
.end()) {
2255 if ((*prev
)->locked()) {
2259 if (region
->position() != (*prev
)->last_frame() + 1) {
2260 /* they didn't used to touch, so after shuffle,
2261 just have them swap positions.
2263 new_pos
= region
->position();
2265 /* they used to touch, so after shuffle,
2266 make sure they still do. put the earlier
2267 one where the later one will end after
2269 new_pos
= (*prev
)->position() + region
->length();
2272 region
->set_position ((*prev
)->position(), this);
2273 (*prev
)->set_position (new_pos
, this);
2275 /* avoid a full sort */
2277 regions
.erase (i
); // remove region
2278 regions
.insert (prev
, region
); // insert region before prev
2294 check_dependents (region
, false);
2302 Playlist::region_is_shuffle_constrained (boost::shared_ptr
<Region
>)
2304 RegionLock
rlock (const_cast<Playlist
*> (this));
2306 if (regions
.size() > 1) {
2314 Playlist::update_after_tempo_map_change ()
2316 RegionLock
rlock (const_cast<Playlist
*> (this));
2317 RegionList
copy (regions
);
2321 for (RegionList::iterator i
= copy
.begin(); i
!= copy
.end(); ++i
) {
2322 (*i
)->update_position_after_tempo_map_change ();