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;
44 //using namespace sigc;
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)
101 other.copy_regions (regions);
103 for (list<Region*>::iterator x = regions.begin(); x != regions.end(); ++x) {
104 (*x)->set_playlist (this);
108 Playlist::Playlist (const Playlist& other, jack_nframes_t start, jack_nframes_t cnt, string str, bool hide)
109 : _name (str), _session (other._session), _orig_diskstream_id(other._orig_diskstream_id)
111 RegionLock rlock2 (&((Playlist&)other));
113 jack_nframes_t end = start + cnt - 1;
117 for (RegionList::const_iterator i = other.regions.begin(); i != other.regions.end(); i++) {
121 jack_nframes_t offset = 0;
122 jack_nframes_t position = 0;
123 jack_nframes_t len = 0;
129 overlap = region->coverage (start, end);
135 case OverlapInternal:
136 offset = start - region->position();
143 position = region->position() - start;
144 len = end - region->position();
148 offset = start - region->position();
150 len = region->length() - offset;
153 case OverlapExternal:
155 position = region->position() - start;
156 len = region->length();
160 _session.region_name (new_name, region->name(), false);
162 new_region = createRegion (*region, offset, len, new_name, region->layer(), region->flags());
164 add_region_internal (new_region, position, true);
167 /* this constructor does NOT notify others (session) */
174 InUse (this, true); /* EMIT SIGNAL */
184 InUse (this, false); /* EMIT SIGNAL */
187 /* nobody knows we exist */
195 Playlist::copy_regions (RegionList& newlist) const
197 RegionLock rlock (const_cast<Playlist *> (this));
199 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
200 newlist.push_back (createRegion (**i));
205 Playlist::init (bool hide)
207 atomic_set (&block_notifications, 0);
208 atomic_set (&ignore_state_changes, 0);
209 pending_modified = false;
210 pending_length = false;
215 in_set_state = false;
216 _edit_mode = _session.get_edit_mode();
218 in_partition = false;
220 _read_data_count = 0;
222 save_on_thaw = false;
223 layer_op_counter = 0;
226 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
229 Playlist::Playlist (const Playlist& pl)
230 : _session (pl._session)
232 fatal << _("playlist const copy constructor called") << endmsg;
235 Playlist::Playlist (Playlist& pl)
236 : _session (pl._session)
238 fatal << _("playlist non-const copy constructor called") << endmsg;
241 Playlist::~Playlist ()
246 Playlist::set_name (const string& str)
248 /* in a typical situation, a playlist is being used
249 by one diskstream and also is referenced by the
250 Session. if there are more references than that,
251 then don't change the name.
259 NameChanged(); /* EMIT SIGNAL */
262 /***********************************************************************
263 CHANGE NOTIFICATION HANDLING
265 Notifications must be delayed till the region_lock is released. This
266 is necessary because handlers for the signals may need to acquire
267 the lock (e.g. to read from the playlist).
268 ***********************************************************************/
273 delay_notifications ();
274 atomic_inc (&ignore_state_changes);
280 atomic_dec (&ignore_state_changes);
281 release_notifications ();
286 Playlist::delay_notifications ()
288 atomic_inc (&block_notifications);
289 freeze_length = _get_maximum_extent();
293 Playlist::release_notifications ()
295 if (atomic_dec_and_test(&block_notifications)) {
296 flush_notifications ();
302 Playlist::notify_modified ()
304 if (holding_state ()) {
305 pending_modified = true;
307 pending_modified = false;
308 Modified(); /* EMIT SIGNAL */
313 Playlist::notify_region_removed (Region *r)
315 if (holding_state ()) {
316 pending_removals.insert (pending_removals.end(), r);
318 RegionRemoved (r); /* EMIT SIGNAL */
319 /* this might not be true, but we have to act
320 as though it could be.
322 LengthChanged (); /* EMIT SIGNAL */
323 Modified (); /* EMIT SIGNAL */
328 Playlist::notify_region_added (Region *r)
330 if (holding_state()) {
331 pending_adds.insert (pending_adds.end(), r);
333 RegionAdded (r); /* EMIT SIGNAL */
334 /* this might not be true, but we have to act
335 as though it could be.
337 LengthChanged (); /* EMIT SIGNAL */
338 Modified (); /* EMIT SIGNAL */
343 Playlist::notify_length_changed ()
345 if (holding_state ()) {
346 pending_length = true;
348 LengthChanged(); /* EMIT SIGNAL */
349 Modified (); /* EMIT SIGNAL */
354 Playlist::flush_notifications ()
356 RegionList::iterator r;
357 RegionList::iterator a;
358 set<Region*> dependent_checks_needed;
367 /* we have no idea what order the regions ended up in pending
368 bounds (it could be based on selection order, for example).
369 so, to preserve layering in the "most recently moved is higher"
370 model, sort them by existing layer, then timestamp them.
373 // RegionSortByLayer cmp;
374 // pending_bounds.sort (cmp);
376 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
377 if (_session.get_layer_model() == Session::MoveAddHigher) {
378 timestamp_layer_op (**r);
380 pending_length = true;
384 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
385 dependent_checks_needed.insert (*r);
386 /* don't increment n again - its the same list */
389 for (a = pending_adds.begin(); a != pending_adds.end(); ++a) {
390 dependent_checks_needed.insert (*a);
391 RegionAdded (*a); /* EMIT SIGNAL */
395 for (set<Region*>::iterator x = dependent_checks_needed.begin(); x != dependent_checks_needed.end(); ++x) {
396 check_dependents (**x, false);
399 for (r = pending_removals.begin(); r != pending_removals.end(); ++r) {
400 remove_dependents (**r);
401 RegionRemoved (*r); /* EMIT SIGNAL */
405 if ((freeze_length != _get_maximum_extent()) || pending_length) {
407 LengthChanged(); /* EMIT SIGNAL */
411 if (n || pending_modified) {
414 pending_modified = false;
415 Modified (); /* EMIT SIGNAL */
418 pending_adds.clear ();
419 pending_removals.clear ();
420 pending_bounds.clear ();
423 save_on_thaw = false;
424 save_state (last_save_reason);
430 /*************************************************************
432 *************************************************************/
435 Playlist::add_region (const Region& region, jack_nframes_t position, float times, bool with_save)
437 RegionLock rlock (this);
439 times = fabs (times);
441 int itimes = (int) floor (times);
443 jack_nframes_t pos = position;
446 add_region_internal (const_cast<Region*>(®ion), pos, true);
447 pos += region.length();
451 /* later regions will all be spliced anyway */
453 if (!holding_state ()) {
454 possibly_splice_unlocked ();
457 /* note that itimes can be zero if we being asked to just
458 insert a single fraction of the region.
461 for (int i = 0; i < itimes; ++i) {
462 Region *copy = createRegion (region);
463 add_region_internal (copy, pos, true);
464 pos += region.length();
467 if (floor (times) != times) {
468 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
470 _session.region_name (name, region.name(), false);
471 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
472 add_region_internal (sub, pos, true);
476 maybe_save_state (_("add region"));
481 Playlist::add_region_internal (Region *region, jack_nframes_t position, bool delay_sort)
483 RegionSortByPosition cmp;
484 jack_nframes_t old_length = 0;
486 // cerr << "adding region " << region->name() << " at " << position << endl;
488 if (!holding_state()) {
489 old_length = _get_maximum_extent();
492 region->set_playlist (this);
493 region->set_position (position, this);
494 region->lock_sources ();
496 timestamp_layer_op (*region);
498 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
500 if (!holding_state () && !in_set_state) {
501 /* layers get assigned from XML state */
505 /* we need to notify the existence of new region before checking dependents. Ick. */
507 notify_region_added (region);
509 if (!holding_state ()) {
510 check_dependents (*region, false);
511 if (old_length != _get_maximum_extent()) {
512 notify_length_changed ();
516 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy), region));
520 Playlist::replace_region (Region& old, Region& newr, jack_nframes_t pos)
522 RegionLock rlock (this);
524 remove_region_internal (&old);
525 add_region_internal (&newr, pos);
527 if (!holding_state ()) {
528 possibly_splice_unlocked ();
531 maybe_save_state (_("replace region"));
535 Playlist::remove_region (Region *region)
537 RegionLock rlock (this);
538 remove_region_internal (region);
540 if (!holding_state ()) {
541 possibly_splice_unlocked ();
544 maybe_save_state (_("remove region"));
548 Playlist::remove_region_internal (Region *region, bool delay_sort)
550 RegionList::iterator i;
551 jack_nframes_t old_length = 0;
553 // cerr << "removing region " << region->name() << endl;
555 if (!holding_state()) {
556 old_length = _get_maximum_extent();
559 for (i = regions.begin(); i != regions.end(); ++i) {
564 if (!holding_state ()) {
566 remove_dependents (*region);
568 if (old_length != _get_maximum_extent()) {
569 notify_length_changed ();
573 notify_region_removed (region);
581 Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level)
585 partition_internal (start, end, false, thawlist);
587 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
588 (*i)->thaw ("separation");
591 maybe_save_state (_("separate"));
595 Playlist::partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist)
597 RegionLock rlock (this);
601 RegionList::iterator tmp;
603 jack_nframes_t pos1, pos2, pos3, pos4;
604 RegionList new_regions;
608 /* need to work from a copy, because otherwise the regions we add during the process
609 get operated on as well.
612 RegionList copy = regions;
614 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
621 if (current->first_frame() == start && current->last_frame() == end) {
623 remove_region_internal (current);
628 if ((overlap = current->coverage (start, end)) == OverlapNone) {
632 pos1 = current->position();
635 pos4 = current->last_frame();
637 if (overlap == OverlapInternal) {
639 /* split: we need 3 new regions, the front, middle and end.
640 cut: we need 2 regions, the front and end.
645 ---------------*************************------------
648 ---------------*****++++++++++++++++====------------
650 ---------------*****----------------====------------
656 /* "middle" ++++++ */
658 _session.region_name (new_name, current->name(), false);
659 region = createRegion (*current, pos2 - pos1, pos3 - pos2, new_name,
660 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
661 add_region_internal (region, start, true);
662 new_regions.push_back (region);
667 _session.region_name (new_name, current->name(), false);
668 region = createRegion (*current, pos3 - pos1, pos4 - pos3, new_name,
669 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
671 add_region_internal (region, end, true);
672 new_regions.push_back (region);
677 thawlist.push_back (current);
678 current->trim_end (pos2, this);
680 } else if (overlap == OverlapEnd) {
684 ---------------*************************------------
687 ---------------**************+++++++++++------------
689 ---------------**************-----------------------
697 _session.region_name (new_name, current->name(), false);
698 region = createRegion (*current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
699 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
700 add_region_internal (region, start, true);
701 new_regions.push_back (region);
707 thawlist.push_back (current);
708 current->trim_end (pos2, this);
710 } else if (overlap == OverlapStart) {
712 /* split: we need 2 regions: the front and the end.
713 cut: just trim current to skip the cut area
718 ---------------*************************------------
722 ---------------****+++++++++++++++++++++------------
724 -------------------*********************------------
731 _session.region_name (new_name, current->name(), false);
732 region = createRegion (*current, 0, pos3 - pos1, new_name,
733 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
734 add_region_internal (region, pos1, true);
735 new_regions.push_back (region);
741 thawlist.push_back (current);
742 current->trim_front (pos3, this);
744 } else if (overlap == OverlapExternal) {
746 /* split: no split required.
747 cut: remove the region.
752 ---------------*************************------------
756 ---------------*************************------------
758 ----------------------------------------------------
763 remove_region_internal (current);
765 new_regions.push_back (current);
769 in_partition = false;
771 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
772 check_dependents (**i, false);
777 Playlist::cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
781 jack_nframes_t start;
783 if (ranges.empty()) {
787 start = ranges.front().start;
790 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
792 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
794 if (i == ranges.begin()) {
798 /* paste the next section into the nascent playlist,
799 offset to reflect the start of the first range we
803 ret->paste (*pl, (*i).start - start, 1.0f);
809 /* manually notify session of new playlist here
810 because the playlists were constructed without notifying
812 PlaylistCreated (ret);
819 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
821 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::cut;
822 return cut_copy (pmf, ranges, result_is_hidden);
826 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
828 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::copy;
829 return cut_copy (pmf, ranges, result_is_hidden);
833 Playlist::cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
839 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
840 string new_name = _name;
844 if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
848 partition_internal (start, start+cnt-1, true, thawlist);
851 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
852 (*i)->thaw ("playlist cut");
855 maybe_save_state (_("cut"));
861 Playlist::copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
865 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
866 string new_name = _name;
870 cnt = min (_get_maximum_extent() - start, cnt);
871 return copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
875 Playlist::paste (Playlist& other, jack_nframes_t position, float times)
877 times = fabs (times);
878 jack_nframes_t old_length;
881 RegionLock rl1 (this);
882 RegionLock rl2 (&other);
884 old_length = _get_maximum_extent();
886 int itimes = (int) floor (times);
887 jack_nframes_t pos = position;
888 jack_nframes_t shift = other._get_maximum_extent();
889 layer_t top_layer = regions.size();
892 for (RegionList::iterator i = other.regions.begin(); i != other.regions.end(); ++i) {
893 Region *copy_of_region = createRegion (**i);
895 /* put these new regions on top of all existing ones, but preserve
896 the ordering they had in the original playlist.
899 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
900 add_region_internal (copy_of_region, copy_of_region->position() + pos);
905 possibly_splice_unlocked ();
907 /* XXX shall we handle fractional cases at some point? */
909 if (old_length != _get_maximum_extent()) {
910 notify_length_changed ();
916 maybe_save_state (_("paste"));
923 Playlist::duplicate (Region& region, jack_nframes_t position, float times)
925 times = fabs (times);
927 RegionLock rl (this);
928 int itimes = (int) floor (times);
929 jack_nframes_t pos = position;
932 Region *copy = createRegion (region);
933 add_region_internal (copy, pos, true);
934 pos += region.length();
937 if (floor (times) != times) {
938 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
940 _session.region_name (name, region.name(), false);
941 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
942 add_region_internal (sub, pos, true);
945 maybe_save_state (_("duplicate"));
949 Playlist::split_region (Region& region, jack_nframes_t playlist_position)
951 RegionLock rl (this);
953 if (!region.covers (playlist_position)) {
957 if (region.position() == playlist_position ||
958 region.last_frame() == playlist_position) {
962 if (remove_region_internal (®ion, true)) {
968 jack_nframes_t before;
969 jack_nframes_t after;
973 before = playlist_position - region.position();
974 after = region.length() - before;
976 _session.region_name (before_name, region.name(), false);
977 left = createRegion (region, 0, before, before_name, region.layer(), Region::Flag (region.flags()|Region::LeftOfSplit));
979 _session.region_name (after_name, region.name(), false);
980 right = createRegion (region, before, after, after_name, region.layer(), Region::Flag (region.flags()|Region::RightOfSplit));
982 add_region_internal (left, region.position(), true);
983 add_region_internal (right, region.position() + before);
985 maybe_save_state (_("split"));
989 Playlist::possibly_splice ()
991 if (_edit_mode == Splice) {
997 Playlist::possibly_splice_unlocked ()
999 if (_edit_mode == Splice) {
1005 Playlist::splice_locked ()
1008 RegionLock rl (this);
1012 notify_length_changed ();
1016 Playlist::splice_unlocked ()
1019 notify_length_changed ();
1023 Playlist::core_splice ()
1027 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1029 RegionList::iterator next;
1034 if (next == regions.end()) {
1038 (*next)->set_position ((*i)->last_frame() + 1, this);
1045 Playlist::region_bounds_changed (Change what_changed, Region *region)
1047 if (in_set_state || _splicing || _nudging) {
1051 if (what_changed & ARDOUR::PositionChanged) {
1053 /* remove it from the list then add it back in
1054 the right place again.
1057 RegionSortByPosition cmp;
1059 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1061 if (i == regions.end()) {
1062 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1063 _name, region->name())
1069 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp),
1074 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1076 if (holding_state ()) {
1077 pending_bounds.push_back (region);
1079 if (_session.get_layer_model() == Session::MoveAddHigher) {
1080 /* it moved or changed length, so change the timestamp */
1081 timestamp_layer_op (*region);
1085 check_dependents (*region, false);
1086 notify_length_changed ();
1093 Playlist::region_changed_proxy (Change what_changed, Region* region)
1095 /* this makes a virtual call to the right kind of playlist ... */
1097 region_changed (what_changed, region);
1101 Playlist::region_changed (Change what_changed, Region* region)
1103 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1106 if (in_set_state || in_flush) {
1111 if (what_changed & BoundsChanged) {
1112 region_bounds_changed (what_changed, region);
1113 save = !(_splicing || _nudging);
1116 if ((what_changed & Region::MuteChanged) &&
1117 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1118 check_dependents (*region, false);
1121 if (what_changed & our_interests) {
1130 Playlist::clear (bool with_delete, bool with_save)
1132 RegionList::iterator i;
1136 RegionLock rl (this);
1141 for (i = tmp.begin(); i != tmp.end(); ++i) {
1142 notify_region_removed (*i);
1149 maybe_save_state (_("clear"));
1153 /***********************************************************************
1155 **********************************************************************/
1157 Playlist::RegionList *
1158 Playlist::regions_at (jack_nframes_t frame)
1161 RegionLock rlock (this);
1162 return find_regions_at (frame);
1166 Playlist::top_region_at (jack_nframes_t frame)
1169 RegionLock rlock (this);
1170 RegionList *rlist = find_regions_at (frame);
1173 if (rlist->size()) {
1174 RegionSortByLayer cmp;
1176 region = rlist->back();
1183 Playlist::RegionList *
1184 Playlist::find_regions_at (jack_nframes_t frame)
1186 RegionList *rlist = new RegionList;
1188 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1189 if ((*i)->covers (frame)) {
1190 rlist->push_back (*i);
1197 Playlist::RegionList *
1198 Playlist::regions_touched (jack_nframes_t start, jack_nframes_t end)
1200 RegionLock rlock (this);
1201 RegionList *rlist = new RegionList;
1203 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1204 if ((*i)->coverage (start, end) != OverlapNone) {
1205 rlist->push_back (*i);
1215 Playlist::find_next_region (jack_nframes_t frame, RegionPoint point, int dir)
1217 RegionLock rlock (this);
1219 jack_nframes_t closest = max_frames;
1221 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1223 jack_nframes_t distance;
1225 jack_nframes_t pos = 0;
1229 pos = r->first_frame ();
1232 pos = r->last_frame ();
1235 pos = r->adjust_to_sync (r->first_frame());
1240 case 1: /* forwards */
1243 if ((distance = pos - frame) < closest) {
1251 default: /* backwards */
1254 if ((distance = frame - pos) < closest) {
1266 /***********************************************************************/
1271 Playlist::mark_session_dirty ()
1273 if (!in_set_state && !holding_state ()) {
1274 _session.set_dirty();
1279 Playlist::set_state (const XMLNode& node)
1281 in_set_state = true;
1285 XMLNodeConstIterator niter;
1286 XMLPropertyList plist;
1287 XMLPropertyConstIterator piter;
1292 clear (false, false);
1294 if (node.name() != "Playlist") {
1295 in_set_state = false;
1299 plist = node.properties();
1301 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1305 if (prop->name() == X_("name")) {
1306 _name = prop->value();
1307 } else if (prop->name() == X_("orig_diskstream_id")) {
1308 sscanf (prop->value().c_str(), "%" PRIu64, &_orig_diskstream_id);
1309 } else if (prop->name() == X_("frozen")) {
1310 _frozen = (prop->value() == X_("yes"));
1314 nlist = node.children();
1316 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1320 if (child->name() == "Region") {
1322 if ((region = createRegion (_session, *child, true)) == 0) {
1323 error << _("Playlist: cannot create region from state file") << endmsg;
1327 add_region (*region, region->position(), 1.0, false);
1332 /* update dependents, which was not done during add_region_internal
1333 due to in_set_state being true
1336 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1337 check_dependents (**r, false);
1340 in_set_state = false;
1346 Playlist::get_state()
1352 Playlist::get_template()
1354 return state(false);
1358 Playlist::state (bool full_state)
1360 XMLNode *node = new XMLNode (X_("Playlist"));
1363 node->add_property (X_("name"), _name);
1365 snprintf (buf, sizeof(buf), "%" PRIu64, _orig_diskstream_id);
1366 node->add_property (X_("orig_diskstream_id"), buf);
1367 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1370 RegionLock rlock (this, false);
1372 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1373 node->add_child_nocopy ((*i)->get_state());
1378 node->add_child_copy (*_extra_xml);
1385 Playlist::empty() const
1387 return regions.empty();
1391 Playlist::get_maximum_extent () const
1393 RegionLock rlock (const_cast<Playlist *>(this));
1394 return _get_maximum_extent ();
1398 Playlist::_get_maximum_extent () const
1400 RegionList::const_iterator i;
1401 jack_nframes_t max_extent = 0;
1402 jack_nframes_t end = 0;
1404 for (i = regions.begin(); i != regions.end(); ++i) {
1405 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1414 Playlist::bump_name (string name, Session &session)
1416 string newname = name;
1419 newname = Playlist::bump_name_once (newname);
1420 } while (session.playlist_by_name(newname)!=NULL);
1426 Playlist::bump_name_once (string name)
1428 string::size_type period;
1431 if ((period = name.find_last_of ('.')) == string::npos) {
1438 sscanf (name.substr (period+1).c_str(), "%d", &version);
1439 snprintf (buf, sizeof(buf), "%d", version+1);
1441 newname = name.substr (0, period+1);
1449 Playlist::top_layer() const
1451 RegionLock rlock (const_cast<Playlist *> (this));
1454 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1455 top = max (top, (*i)->layer());
1461 Playlist::set_edit_mode (EditMode mode)
1466 /********************
1468 ********************/
1471 Playlist::relayer ()
1473 RegionList::iterator i;
1476 /* don't send multiple Modified notifications
1477 when multiple regions are relayered.
1482 if (_session.get_layer_model() == Session::MoveAddHigher ||
1483 _session.get_layer_model() == Session::AddHigher) {
1485 RegionSortByLastLayerOp cmp;
1486 RegionList copy = regions;
1490 for (i = copy.begin(); i != copy.end(); ++i) {
1491 (*i)->set_layer (layer++);
1496 /* Session::LaterHigher model */
1498 for (i = regions.begin(); i != regions.end(); ++i) {
1499 (*i)->set_layer (layer++);
1503 /* sending Modified means that various kinds of layering
1504 models operate correctly at the GUI
1505 level. slightly inefficient, but only slightly.
1507 We force a Modified signal here in case no layers actually
1516 /* XXX these layer functions are all deprecated */
1519 Playlist::raise_region (Region& region)
1521 uint32_t rsz = regions.size();
1522 layer_t target = region.layer() + 1U;
1524 if (target >= rsz) {
1525 /* its already at the effective top */
1529 move_region_to_layer (target, region, 1);
1533 Playlist::lower_region (Region& region)
1535 if (region.layer() == 0) {
1536 /* its already at the bottom */
1540 layer_t target = region.layer() - 1U;
1542 move_region_to_layer (target, region, -1);
1546 Playlist::raise_region_to_top (Region& region)
1548 /* does nothing useful if layering mode is later=higher */
1549 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1550 (_session.get_layer_model() == Session::AddHigher)) {
1551 timestamp_layer_op (region);
1557 Playlist::lower_region_to_bottom (Region& region)
1559 /* does nothing useful if layering mode is later=higher */
1560 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1561 (_session.get_layer_model() == Session::AddHigher)) {
1562 region.set_last_layer_op (0);
1568 Playlist::move_region_to_layer (layer_t target_layer, Region& region, int dir)
1570 RegionList::iterator i;
1571 typedef pair<Region*,layer_t> LayerInfo;
1572 list<LayerInfo> layerinfo;
1576 RegionLock rlock (const_cast<Playlist *> (this));
1578 for (i = regions.begin(); i != regions.end(); ++i) {
1580 if (®ion == *i) {
1586 /* region is moving up, move all regions on intermediate layers
1590 if ((*i)->layer() > region.layer() && (*i)->layer() <= target_layer) {
1591 dest = (*i)->layer() - 1;
1598 /* region is moving down, move all regions on intermediate layers
1602 if ((*i)->layer() < region.layer() && (*i)->layer() >= target_layer) {
1603 dest = (*i)->layer() + 1;
1613 newpair.second = dest;
1615 layerinfo.push_back (newpair);
1619 /* now reset the layers without holding the region lock */
1621 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1622 x->first->set_layer (x->second);
1625 region.set_layer (target_layer);
1627 /* now check all dependents */
1629 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1630 check_dependents (*(x->first), false);
1633 check_dependents (region, false);
1639 Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards)
1641 RegionList::iterator i;
1642 jack_nframes_t new_pos;
1648 RegionLock rlock (const_cast<Playlist *> (this));
1650 for (i = regions.begin(); i != regions.end(); ++i) {
1652 if ((*i)->position() >= start) {
1656 if ((*i)->last_frame() > max_frames - distance) {
1657 new_pos = max_frames - (*i)->length();
1659 new_pos = (*i)->position() + distance;
1664 if ((*i)->position() > distance) {
1665 new_pos = (*i)->position() - distance;
1671 (*i)->set_position (new_pos, this);
1679 maybe_save_state (_("nudged"));
1680 notify_length_changed ();
1686 Playlist::find_region (id_t id) const
1688 RegionLock rlock (const_cast<Playlist*> (this));
1689 RegionList::const_iterator i;
1691 for (i = regions.begin(); i != regions.end(); ++i) {
1692 if ((*i)->id() == id) {
1701 Playlist::save_state (std::string why)
1703 if (!in_set_state) {
1704 StateManager::save_state (why);
1709 Playlist::dump () const
1713 cerr << "Playlist \"" << _name << "\" " << endl
1714 << regions.size() << " regions "
1717 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1719 cerr << " " << r->name() << " ["
1720 << r->start() << "+" << r->length()
1730 Playlist::set_frozen (bool yn)
1736 Playlist::timestamp_layer_op (Region& region)
1738 // struct timeval tv;
1739 // gettimeofday (&tv, 0);
1740 region.set_last_layer_op (++layer_op_counter);
1744 Playlist::maybe_save_state (string why)
1746 if (holding_state ()) {
1747 save_on_thaw = true;
1748 last_save_reason = why;