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.
29 #include <sigc++/bind.h>
31 #include <pbd/failed_constructor.h>
32 #include <pbd/stl_delete.h>
33 #include <pbd/xml++.h>
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
43 using namespace ARDOUR;
46 sigc::signal<void,Playlist*> Playlist::PlaylistCreated;
48 struct ShowMeTheList {
49 ShowMeTheList (Playlist *pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
57 struct RegionSortByLayer {
58 bool operator() (Region *a, Region *b) {
59 return a->layer() < b->layer();
63 struct RegionSortByPosition {
64 bool operator() (Region *a, Region *b) {
65 return a->position() < b->position();
69 struct RegionSortByLastLayerOp {
70 bool operator() (Region *a, Region *b) {
71 return a->last_layer_op() < b->last_layer_op();
75 Playlist::Playlist (Session& sess, string nom, bool hide)
80 _orig_diskstream_id = 0;
84 Playlist::Playlist (Session& sess, const XMLNode& node, bool hide)
88 _name = "unnamed"; /* reset by set_state */
89 _orig_diskstream_id = 0;
91 if (set_state (node)) {
92 throw failed_constructor();
96 Playlist::Playlist (const Playlist& other, string namestr, bool hide)
97 : _name (namestr), _session (other._session), _orig_diskstream_id(other._orig_diskstream_id)
102 other.copy_regions (tmp);
106 for (list<Region*>::iterator x = tmp.begin(); x != tmp.end(); ++x) {
107 add_region_internal( (*x), (*x)->position() );
110 in_set_state = false;
112 _splicing = other._splicing;
113 _nudging = other._nudging;
114 _edit_mode = other._edit_mode;
116 in_set_state = false;
118 in_partition = false;
120 _read_data_count = 0;
121 _frozen = other._frozen;
122 save_on_thaw = false;
124 layer_op_counter = other.layer_op_counter;
125 freeze_length = other.freeze_length;
129 Playlist::Playlist (const Playlist& other, jack_nframes_t start, jack_nframes_t cnt, string str, bool hide)
130 : _name (str), _session (other._session), _orig_diskstream_id(other._orig_diskstream_id)
132 RegionLock rlock2 (&((Playlist&)other));
134 jack_nframes_t end = start + cnt - 1;
138 for (RegionList::const_iterator i = other.regions.begin(); i != other.regions.end(); i++) {
142 jack_nframes_t offset = 0;
143 jack_nframes_t position = 0;
144 jack_nframes_t len = 0;
150 overlap = region->coverage (start, end);
156 case OverlapInternal:
157 offset = start - region->position();
164 position = region->position() - start;
165 len = end - region->position();
169 offset = start - region->position();
171 len = region->length() - offset;
174 case OverlapExternal:
176 position = region->position() - start;
177 len = region->length();
181 _session.region_name (new_name, region->name(), false);
183 new_region = createRegion (*region, offset, len, new_name, region->layer(), region->flags());
185 add_region_internal (new_region, position, true);
188 /* this constructor does NOT notify others (session) */
195 InUse (this, true); /* EMIT SIGNAL */
205 InUse (this, false); /* EMIT SIGNAL */
208 /* nobody knows we exist */
216 Playlist::copy_regions (RegionList& newlist) const
218 RegionLock rlock (const_cast<Playlist *> (this));
220 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
221 newlist.push_back (createRegion (**i));
226 Playlist::init (bool hide)
228 g_atomic_int_set (&block_notifications, 0);
229 g_atomic_int_set (&ignore_state_changes, 0);
230 pending_modified = false;
231 pending_length = false;
236 in_set_state = false;
237 _edit_mode = _session.get_edit_mode();
239 in_partition = false;
241 _read_data_count = 0;
243 save_on_thaw = false;
244 layer_op_counter = 0;
247 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
250 Playlist::Playlist (const Playlist& pl)
251 : _session (pl._session)
253 fatal << _("playlist const copy constructor called") << endmsg;
256 Playlist::Playlist (Playlist& pl)
257 : _session (pl._session)
259 fatal << _("playlist non-const copy constructor called") << endmsg;
262 Playlist::~Playlist ()
267 Playlist::set_name (const string& str)
269 /* in a typical situation, a playlist is being used
270 by one diskstream and also is referenced by the
271 Session. if there are more references than that,
272 then don't change the name.
280 NameChanged(); /* EMIT SIGNAL */
283 /***********************************************************************
284 CHANGE NOTIFICATION HANDLING
286 Notifications must be delayed till the region_lock is released. This
287 is necessary because handlers for the signals may need to acquire
288 the lock (e.g. to read from the playlist).
289 ***********************************************************************/
294 delay_notifications ();
295 g_atomic_int_inc (&ignore_state_changes);
301 g_atomic_int_dec_and_test (&ignore_state_changes);
302 release_notifications ();
307 Playlist::delay_notifications ()
309 g_atomic_int_inc (&block_notifications);
310 freeze_length = _get_maximum_extent();
314 Playlist::release_notifications ()
316 if (g_atomic_int_dec_and_test (&block_notifications)) {
317 flush_notifications ();
323 Playlist::notify_modified ()
325 if (holding_state ()) {
326 pending_modified = true;
328 pending_modified = false;
329 Modified(); /* EMIT SIGNAL */
334 Playlist::notify_region_removed (Region *r)
336 if (holding_state ()) {
337 pending_removals.insert (pending_removals.end(), r);
339 RegionRemoved (r); /* EMIT SIGNAL */
340 /* this might not be true, but we have to act
341 as though it could be.
343 LengthChanged (); /* EMIT SIGNAL */
344 Modified (); /* EMIT SIGNAL */
349 Playlist::notify_region_added (Region *r)
351 if (holding_state()) {
352 pending_adds.insert (pending_adds.end(), r);
354 RegionAdded (r); /* EMIT SIGNAL */
355 /* this might not be true, but we have to act
356 as though it could be.
358 LengthChanged (); /* EMIT SIGNAL */
359 Modified (); /* EMIT SIGNAL */
364 Playlist::notify_length_changed ()
366 if (holding_state ()) {
367 pending_length = true;
369 LengthChanged(); /* EMIT SIGNAL */
370 Modified (); /* EMIT SIGNAL */
375 Playlist::flush_notifications ()
377 RegionList::iterator r;
378 RegionList::iterator a;
379 set<Region*> dependent_checks_needed;
388 /* we have no idea what order the regions ended up in pending
389 bounds (it could be based on selection order, for example).
390 so, to preserve layering in the "most recently moved is higher"
391 model, sort them by existing layer, then timestamp them.
394 // RegionSortByLayer cmp;
395 // pending_bounds.sort (cmp);
397 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
398 if (_session.get_layer_model() == Session::MoveAddHigher) {
399 timestamp_layer_op (**r);
401 pending_length = true;
405 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
406 dependent_checks_needed.insert (*r);
407 /* don't increment n again - its the same list */
410 for (a = pending_adds.begin(); a != pending_adds.end(); ++a) {
411 dependent_checks_needed.insert (*a);
412 RegionAdded (*a); /* EMIT SIGNAL */
416 for (set<Region*>::iterator x = dependent_checks_needed.begin(); x != dependent_checks_needed.end(); ++x) {
417 check_dependents (**x, false);
420 for (r = pending_removals.begin(); r != pending_removals.end(); ++r) {
421 remove_dependents (**r);
422 RegionRemoved (*r); /* EMIT SIGNAL */
426 if ((freeze_length != _get_maximum_extent()) || pending_length) {
428 LengthChanged(); /* EMIT SIGNAL */
432 if (n || pending_modified) {
437 pending_modified = false;
438 Modified (); /* EMIT SIGNAL */
441 pending_adds.clear ();
442 pending_removals.clear ();
443 pending_bounds.clear ();
446 save_on_thaw = false;
447 save_state (last_save_reason);
453 /*************************************************************
455 *************************************************************/
458 Playlist::add_region (const Region& region, jack_nframes_t position, float times, bool with_save)
460 RegionLock rlock (this);
462 times = fabs (times);
464 int itimes = (int) floor (times);
466 jack_nframes_t pos = position;
469 add_region_internal (const_cast<Region*>(®ion), pos, true);
470 pos += region.length();
474 /* later regions will all be spliced anyway */
476 if (!holding_state ()) {
477 possibly_splice_unlocked ();
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 Region *copy = createRegion (region);
486 add_region_internal (copy, pos, true);
487 pos += region.length();
490 if (floor (times) != times) {
491 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
493 _session.region_name (name, region.name(), false);
494 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
495 add_region_internal (sub, pos, true);
499 maybe_save_state (_("add region"));
504 Playlist::add_region_internal (Region *region, jack_nframes_t position, bool delay_sort)
506 RegionSortByPosition cmp;
507 jack_nframes_t old_length = 0;
509 // cerr << "adding region " << region->name() << " at " << position << endl;
511 if (!holding_state()) {
512 old_length = _get_maximum_extent();
515 region->set_playlist (this);
516 region->set_position (position, this);
517 region->lock_sources ();
519 timestamp_layer_op (*region);
521 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
523 if (!holding_state () && !in_set_state) {
524 /* layers get assigned from XML state */
528 /* we need to notify the existence of new region before checking dependents. Ick. */
530 notify_region_added (region);
532 if (!holding_state ()) {
533 check_dependents (*region, false);
534 if (old_length != _get_maximum_extent()) {
535 notify_length_changed ();
539 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy), region));
543 Playlist::replace_region (Region& old, Region& newr, jack_nframes_t pos)
545 RegionLock rlock (this);
547 remove_region_internal (&old);
548 add_region_internal (&newr, pos);
550 if (!holding_state ()) {
551 possibly_splice_unlocked ();
554 maybe_save_state (_("replace region"));
558 Playlist::remove_region (Region *region)
560 RegionLock rlock (this);
561 remove_region_internal (region);
563 if (!holding_state ()) {
564 possibly_splice_unlocked ();
567 maybe_save_state (_("remove region"));
571 Playlist::remove_region_internal (Region *region, bool delay_sort)
573 RegionList::iterator i;
574 jack_nframes_t old_length = 0;
576 // cerr << "removing region " << region->name() << endl;
578 if (!holding_state()) {
579 old_length = _get_maximum_extent();
582 for (i = regions.begin(); i != regions.end(); ++i) {
587 if (!holding_state ()) {
589 remove_dependents (*region);
591 if (old_length != _get_maximum_extent()) {
592 notify_length_changed ();
596 notify_region_removed (region);
604 Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level)
608 partition_internal (start, end, false, thawlist);
610 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
611 (*i)->thaw ("separation");
614 maybe_save_state (_("separate"));
618 Playlist::partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist)
620 RegionLock rlock (this);
624 RegionList::iterator tmp;
626 jack_nframes_t pos1, pos2, pos3, pos4;
627 RegionList new_regions;
631 /* need to work from a copy, because otherwise the regions we add during the process
632 get operated on as well.
635 RegionList copy = regions;
637 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
644 if (current->first_frame() == start && current->last_frame() == end) {
646 remove_region_internal (current);
651 if ((overlap = current->coverage (start, end)) == OverlapNone) {
655 pos1 = current->position();
658 pos4 = current->last_frame();
660 if (overlap == OverlapInternal) {
662 /* split: we need 3 new regions, the front, middle and end.
663 cut: we need 2 regions, the front and end.
668 ---------------*************************------------
671 ---------------*****++++++++++++++++====------------
673 ---------------*****----------------====------------
679 /* "middle" ++++++ */
681 _session.region_name (new_name, current->name(), false);
682 region = createRegion (*current, pos2 - pos1, pos3 - pos2, new_name,
683 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
684 add_region_internal (region, start, true);
685 new_regions.push_back (region);
690 _session.region_name (new_name, current->name(), false);
691 region = createRegion (*current, pos3 - pos1, pos4 - pos3, new_name,
692 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
694 add_region_internal (region, end, true);
695 new_regions.push_back (region);
700 thawlist.push_back (current);
701 current->trim_end (pos2, this);
703 } else if (overlap == OverlapEnd) {
707 ---------------*************************------------
710 ---------------**************+++++++++++------------
712 ---------------**************-----------------------
720 _session.region_name (new_name, current->name(), false);
721 region = createRegion (*current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
722 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
723 add_region_internal (region, start, true);
724 new_regions.push_back (region);
730 thawlist.push_back (current);
731 current->trim_end (pos2, this);
733 } else if (overlap == OverlapStart) {
735 /* split: we need 2 regions: the front and the end.
736 cut: just trim current to skip the cut area
741 ---------------*************************------------
745 ---------------****+++++++++++++++++++++------------
747 -------------------*********************------------
754 _session.region_name (new_name, current->name(), false);
755 region = createRegion (*current, 0, pos3 - pos1, new_name,
756 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
757 add_region_internal (region, pos1, true);
758 new_regions.push_back (region);
764 thawlist.push_back (current);
765 current->trim_front (pos3, this);
767 } else if (overlap == OverlapExternal) {
769 /* split: no split required.
770 cut: remove the region.
775 ---------------*************************------------
779 ---------------*************************------------
781 ----------------------------------------------------
786 remove_region_internal (current);
788 new_regions.push_back (current);
792 in_partition = false;
794 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
795 check_dependents (**i, false);
800 Playlist::cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
804 jack_nframes_t start;
806 if (ranges.empty()) {
810 start = ranges.front().start;
813 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
815 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
817 if (i == ranges.begin()) {
821 /* paste the next section into the nascent playlist,
822 offset to reflect the start of the first range we
826 ret->paste (*pl, (*i).start - start, 1.0f);
832 /* manually notify session of new playlist here
833 because the playlists were constructed without notifying
835 PlaylistCreated (ret);
842 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
844 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::cut;
845 return cut_copy (pmf, ranges, result_is_hidden);
849 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
851 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::copy;
852 return cut_copy (pmf, ranges, result_is_hidden);
856 Playlist::cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
862 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
863 string new_name = _name;
867 if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
871 partition_internal (start, start+cnt-1, true, thawlist);
874 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
875 (*i)->thaw ("playlist cut");
878 maybe_save_state (_("cut"));
884 Playlist::copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
888 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
889 string new_name = _name;
893 cnt = min (_get_maximum_extent() - start, cnt);
894 return copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
898 Playlist::paste (Playlist& other, jack_nframes_t position, float times)
900 times = fabs (times);
901 jack_nframes_t old_length;
904 RegionLock rl1 (this);
905 RegionLock rl2 (&other);
907 old_length = _get_maximum_extent();
909 int itimes = (int) floor (times);
910 jack_nframes_t pos = position;
911 jack_nframes_t shift = other._get_maximum_extent();
912 layer_t top_layer = regions.size();
915 for (RegionList::iterator i = other.regions.begin(); i != other.regions.end(); ++i) {
916 Region *copy_of_region = createRegion (**i);
918 /* put these new regions on top of all existing ones, but preserve
919 the ordering they had in the original playlist.
922 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
923 add_region_internal (copy_of_region, copy_of_region->position() + pos);
928 possibly_splice_unlocked ();
930 /* XXX shall we handle fractional cases at some point? */
932 if (old_length != _get_maximum_extent()) {
933 notify_length_changed ();
939 maybe_save_state (_("paste"));
946 Playlist::duplicate (Region& region, jack_nframes_t position, float times)
948 times = fabs (times);
950 RegionLock rl (this);
951 int itimes = (int) floor (times);
952 jack_nframes_t pos = position;
955 Region *copy = createRegion (region);
956 add_region_internal (copy, pos, true);
957 pos += region.length();
960 if (floor (times) != times) {
961 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
963 _session.region_name (name, region.name(), false);
964 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
965 add_region_internal (sub, pos, true);
968 maybe_save_state (_("duplicate"));
972 Playlist::split_region (Region& region, jack_nframes_t playlist_position)
974 RegionLock rl (this);
976 if (!region.covers (playlist_position)) {
980 if (region.position() == playlist_position ||
981 region.last_frame() == playlist_position) {
987 jack_nframes_t before;
988 jack_nframes_t after;
992 before = playlist_position - region.position();
993 after = region.length() - before;
996 _session.region_name (before_name, region.name(), false);
997 left = createRegion (region, 0, before, before_name, region.layer(), Region::Flag (region.flags()|Region::LeftOfSplit));
999 _session.region_name (after_name, region.name(), false);
1000 right = createRegion (region, before, after, after_name, region.layer(), Region::Flag (region.flags()|Region::RightOfSplit));
1002 add_region_internal (left, region.position(), true);
1003 add_region_internal (right, region.position() + before);
1005 uint64_t orig_layer_op = region.last_layer_op();
1006 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1007 if ((*i)->last_layer_op() > orig_layer_op) {
1008 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1012 left->set_last_layer_op ( orig_layer_op );
1013 right->set_last_layer_op ( orig_layer_op + 1);
1017 finalize_split_region (®ion, left, right);
1019 if (remove_region_internal (®ion, true)) {
1023 maybe_save_state (_("split"));
1027 Playlist::possibly_splice ()
1029 if (_edit_mode == Splice) {
1035 Playlist::possibly_splice_unlocked ()
1037 if (_edit_mode == Splice) {
1043 Playlist::splice_locked ()
1046 RegionLock rl (this);
1050 notify_length_changed ();
1054 Playlist::splice_unlocked ()
1057 notify_length_changed ();
1061 Playlist::core_splice ()
1065 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1067 RegionList::iterator next;
1072 if (next == regions.end()) {
1076 (*next)->set_position ((*i)->last_frame() + 1, this);
1083 Playlist::region_bounds_changed (Change what_changed, Region *region)
1085 if (in_set_state || _splicing || _nudging) {
1089 if (what_changed & ARDOUR::PositionChanged) {
1091 /* remove it from the list then add it back in
1092 the right place again.
1095 RegionSortByPosition cmp;
1097 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1099 if (i == regions.end()) {
1100 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1101 _name, region->name())
1107 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp),
1112 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1114 if (holding_state ()) {
1115 pending_bounds.push_back (region);
1117 if (_session.get_layer_model() == Session::MoveAddHigher) {
1118 /* it moved or changed length, so change the timestamp */
1119 timestamp_layer_op (*region);
1123 check_dependents (*region, false);
1124 notify_length_changed ();
1131 Playlist::region_changed_proxy (Change what_changed, Region* region)
1133 /* this makes a virtual call to the right kind of playlist ... */
1135 region_changed (what_changed, region);
1139 Playlist::region_changed (Change what_changed, Region* region)
1141 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1144 if (in_set_state || in_flush) {
1149 if (what_changed & BoundsChanged) {
1150 region_bounds_changed (what_changed, region);
1151 save = !(_splicing || _nudging);
1154 if ((what_changed & Region::MuteChanged) &&
1155 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1156 check_dependents (*region, false);
1159 if (what_changed & our_interests) {
1168 Playlist::clear (bool with_delete, bool with_save)
1170 RegionList::iterator i;
1174 RegionLock rl (this);
1179 for (i = tmp.begin(); i != tmp.end(); ++i) {
1180 notify_region_removed (*i);
1187 maybe_save_state (_("clear"));
1191 /***********************************************************************
1193 **********************************************************************/
1195 Playlist::RegionList *
1196 Playlist::regions_at (jack_nframes_t frame)
1199 RegionLock rlock (this);
1200 return find_regions_at (frame);
1204 Playlist::top_region_at (jack_nframes_t frame)
1207 RegionLock rlock (this);
1208 RegionList *rlist = find_regions_at (frame);
1211 if (rlist->size()) {
1212 RegionSortByLayer cmp;
1214 region = rlist->back();
1221 Playlist::RegionList *
1222 Playlist::find_regions_at (jack_nframes_t frame)
1224 RegionList *rlist = new RegionList;
1226 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1227 if ((*i)->covers (frame)) {
1228 rlist->push_back (*i);
1235 Playlist::RegionList *
1236 Playlist::regions_touched (jack_nframes_t start, jack_nframes_t end)
1238 RegionLock rlock (this);
1239 RegionList *rlist = new RegionList;
1241 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1242 if ((*i)->coverage (start, end) != OverlapNone) {
1243 rlist->push_back (*i);
1253 Playlist::find_next_region (jack_nframes_t frame, RegionPoint point, int dir)
1255 RegionLock rlock (this);
1257 jack_nframes_t closest = max_frames;
1259 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1261 jack_nframes_t distance;
1263 jack_nframes_t pos = 0;
1267 pos = r->first_frame ();
1270 pos = r->last_frame ();
1273 pos = r->adjust_to_sync (r->first_frame());
1278 case 1: /* forwards */
1281 if ((distance = pos - frame) < closest) {
1289 default: /* backwards */
1292 if ((distance = frame - pos) < closest) {
1304 /***********************************************************************/
1309 Playlist::mark_session_dirty ()
1311 if (!in_set_state && !holding_state ()) {
1312 _session.set_dirty();
1317 Playlist::set_state (const XMLNode& node)
1319 in_set_state = true;
1323 XMLNodeConstIterator niter;
1324 XMLPropertyList plist;
1325 XMLPropertyConstIterator piter;
1330 clear (false, false);
1332 if (node.name() != "Playlist") {
1333 in_set_state = false;
1337 plist = node.properties();
1339 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1343 if (prop->name() == X_("name")) {
1344 _name = prop->value();
1345 } else if (prop->name() == X_("orig_diskstream_id")) {
1346 sscanf (prop->value().c_str(), "%" PRIu64, &_orig_diskstream_id);
1347 } else if (prop->name() == X_("frozen")) {
1348 _frozen = (prop->value() == X_("yes"));
1352 nlist = node.children();
1354 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1358 if (child->name() == "Region") {
1360 if ((region = createRegion (_session, *child, true)) == 0) {
1361 error << _("Playlist: cannot create region from state file") << endmsg;
1365 add_region (*region, region->position(), 1.0, false);
1367 // So that layer_op ordering doesn't get screwed up
1368 region->set_last_layer_op( region->layer());
1374 /* update dependents, which was not done during add_region_internal
1375 due to in_set_state being true
1378 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1379 check_dependents (**r, false);
1382 in_set_state = false;
1388 Playlist::get_state()
1394 Playlist::get_template()
1396 return state(false);
1400 Playlist::state (bool full_state)
1402 XMLNode *node = new XMLNode (X_("Playlist"));
1405 node->add_property (X_("name"), _name);
1407 snprintf (buf, sizeof(buf), "%" PRIu64, _orig_diskstream_id);
1408 node->add_property (X_("orig_diskstream_id"), buf);
1409 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1412 RegionLock rlock (this, false);
1414 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1415 node->add_child_nocopy ((*i)->get_state());
1420 node->add_child_copy (*_extra_xml);
1427 Playlist::empty() const
1429 return regions.empty();
1433 Playlist::get_maximum_extent () const
1435 RegionLock rlock (const_cast<Playlist *>(this));
1436 return _get_maximum_extent ();
1440 Playlist::_get_maximum_extent () const
1442 RegionList::const_iterator i;
1443 jack_nframes_t max_extent = 0;
1444 jack_nframes_t end = 0;
1446 for (i = regions.begin(); i != regions.end(); ++i) {
1447 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1456 Playlist::bump_name (string name, Session &session)
1458 string newname = name;
1461 newname = Playlist::bump_name_once (newname);
1462 } while (session.playlist_by_name(newname)!=NULL);
1468 Playlist::bump_name_once (string name)
1470 string::size_type period;
1473 if ((period = name.find_last_of ('.')) == string::npos) {
1480 sscanf (name.substr (period+1).c_str(), "%d", &version);
1481 snprintf (buf, sizeof(buf), "%d", version+1);
1483 newname = name.substr (0, period+1);
1491 Playlist::top_layer() const
1493 RegionLock rlock (const_cast<Playlist *> (this));
1496 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1497 top = max (top, (*i)->layer());
1503 Playlist::set_edit_mode (EditMode mode)
1508 /********************
1510 ********************/
1513 Playlist::relayer ()
1515 RegionList::iterator i;
1518 /* don't send multiple Modified notifications
1519 when multiple regions are relayered.
1524 if (_session.get_layer_model() == Session::MoveAddHigher ||
1525 _session.get_layer_model() == Session::AddHigher) {
1527 RegionSortByLastLayerOp cmp;
1528 RegionList copy = regions;
1532 for (i = copy.begin(); i != copy.end(); ++i) {
1533 (*i)->set_layer (layer++);
1538 /* Session::LaterHigher model */
1540 for (i = regions.begin(); i != regions.end(); ++i) {
1541 (*i)->set_layer (layer++);
1545 /* sending Modified means that various kinds of layering
1546 models operate correctly at the GUI
1547 level. slightly inefficient, but only slightly.
1549 We force a Modified signal here in case no layers actually
1558 /* XXX these layer functions are all deprecated */
1561 Playlist::raise_region (Region& region)
1563 uint32_t rsz = regions.size();
1564 layer_t target = region.layer() + 1U;
1566 if (target >= rsz) {
1567 /* its already at the effective top */
1571 move_region_to_layer (target, region, 1);
1575 Playlist::lower_region (Region& region)
1577 if (region.layer() == 0) {
1578 /* its already at the bottom */
1582 layer_t target = region.layer() - 1U;
1584 move_region_to_layer (target, region, -1);
1588 Playlist::raise_region_to_top (Region& region)
1590 /* does nothing useful if layering mode is later=higher */
1591 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1592 (_session.get_layer_model() == Session::AddHigher)) {
1593 timestamp_layer_op (region);
1599 Playlist::lower_region_to_bottom (Region& region)
1601 /* does nothing useful if layering mode is later=higher */
1602 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1603 (_session.get_layer_model() == Session::AddHigher)) {
1604 region.set_last_layer_op (0);
1610 Playlist::move_region_to_layer (layer_t target_layer, Region& region, int dir)
1612 RegionList::iterator i;
1613 typedef pair<Region*,layer_t> LayerInfo;
1614 list<LayerInfo> layerinfo;
1618 RegionLock rlock (const_cast<Playlist *> (this));
1620 for (i = regions.begin(); i != regions.end(); ++i) {
1622 if (®ion == *i) {
1628 /* region is moving up, move all regions on intermediate layers
1632 if ((*i)->layer() > region.layer() && (*i)->layer() <= target_layer) {
1633 dest = (*i)->layer() - 1;
1640 /* region is moving down, move all regions on intermediate layers
1644 if ((*i)->layer() < region.layer() && (*i)->layer() >= target_layer) {
1645 dest = (*i)->layer() + 1;
1655 newpair.second = dest;
1657 layerinfo.push_back (newpair);
1661 /* now reset the layers without holding the region lock */
1663 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1664 x->first->set_layer (x->second);
1667 region.set_layer (target_layer);
1669 /* now check all dependents */
1671 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1672 check_dependents (*(x->first), false);
1675 check_dependents (region, false);
1681 Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards)
1683 RegionList::iterator i;
1684 jack_nframes_t new_pos;
1690 RegionLock rlock (const_cast<Playlist *> (this));
1692 for (i = regions.begin(); i != regions.end(); ++i) {
1694 if ((*i)->position() >= start) {
1698 if ((*i)->last_frame() > max_frames - distance) {
1699 new_pos = max_frames - (*i)->length();
1701 new_pos = (*i)->position() + distance;
1706 if ((*i)->position() > distance) {
1707 new_pos = (*i)->position() - distance;
1713 (*i)->set_position (new_pos, this);
1721 maybe_save_state (_("nudged"));
1722 notify_length_changed ();
1728 Playlist::find_region (id_t id) const
1730 RegionLock rlock (const_cast<Playlist*> (this));
1731 RegionList::const_iterator i;
1733 for (i = regions.begin(); i != regions.end(); ++i) {
1734 if ((*i)->id() == id) {
1743 Playlist::save_state (std::string why)
1745 if (!in_set_state) {
1746 StateManager::save_state (why);
1751 Playlist::dump () const
1755 cerr << "Playlist \"" << _name << "\" " << endl
1756 << regions.size() << " regions "
1759 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1761 cerr << " " << r->name() << " ["
1762 << r->start() << "+" << r->length()
1772 Playlist::set_frozen (bool yn)
1778 Playlist::timestamp_layer_op (Region& region)
1780 // struct timeval tv;
1781 // gettimeofday (&tv, 0);
1782 region.set_last_layer_op (++layer_op_counter);
1786 Playlist::maybe_save_state (string why)
1788 if (holding_state ()) {
1789 save_on_thaw = true;
1790 last_save_reason = why;