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 // _session.LayerModelChanged.connect (slot (*this, &Playlist::relayer));
228 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
231 Playlist::Playlist (const Playlist& pl)
232 : _session (pl._session)
234 fatal << _("playlist const copy constructor called") << endmsg;
237 Playlist::Playlist (Playlist& pl)
238 : _session (pl._session)
240 fatal << _("playlist non-const copy constructor called") << endmsg;
243 Playlist::~Playlist ()
248 Playlist::set_name (const string& str)
250 /* in a typical situation, a playlist is being used
251 by one diskstream and also is referenced by the
252 Session. if there are more references than that,
253 then don't change the name.
261 NameChanged(); /* EMIT SIGNAL */
264 /***********************************************************************
265 CHANGE NOTIFICATION HANDLING
267 Notifications must be delayed till the region_lock is released. This
268 is necessary because handlers for the signals may need to acquire
269 the lock (e.g. to read from the playlist).
270 ***********************************************************************/
275 delay_notifications ();
276 atomic_inc (&ignore_state_changes);
282 atomic_dec (&ignore_state_changes);
283 release_notifications ();
288 Playlist::delay_notifications ()
290 atomic_inc (&block_notifications);
291 freeze_length = _get_maximum_extent();
295 Playlist::release_notifications ()
297 if (atomic_dec_and_test(&block_notifications)) {
298 flush_notifications ();
304 Playlist::notify_modified ()
306 if (holding_state ()) {
307 pending_modified = true;
309 pending_modified = false;
310 Modified(); /* EMIT SIGNAL */
315 Playlist::notify_region_removed (Region *r)
317 if (holding_state ()) {
318 pending_removals.insert (pending_removals.end(), r);
320 RegionRemoved (r); /* EMIT SIGNAL */
321 /* this might not be true, but we have to act
322 as though it could be.
324 LengthChanged (); /* EMIT SIGNAL */
325 Modified (); /* EMIT SIGNAL */
330 Playlist::notify_region_added (Region *r)
332 if (holding_state()) {
333 pending_adds.insert (pending_adds.end(), r);
335 RegionAdded (r); /* EMIT SIGNAL */
336 /* this might not be true, but we have to act
337 as though it could be.
339 LengthChanged (); /* EMIT SIGNAL */
340 Modified (); /* EMIT SIGNAL */
345 Playlist::notify_length_changed ()
347 if (holding_state ()) {
348 pending_length = true;
350 LengthChanged(); /* EMIT SIGNAL */
351 Modified (); /* EMIT SIGNAL */
356 Playlist::flush_notifications ()
358 RegionList::iterator r;
359 RegionList::iterator a;
360 set<Region*> dependent_checks_needed;
369 /* we have no idea what order the regions ended up in pending
370 bounds (it could be based on selection order, for example).
371 so, to preserve layering in the "most recently moved is higher"
372 model, sort them by existing layer, then timestamp them.
375 // RegionSortByLayer cmp;
376 // pending_bounds.sort (cmp);
378 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
379 if (_session.get_layer_model() == Session::MoveAddHigher) {
380 timestamp_layer_op (**r);
382 pending_length = true;
386 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
387 dependent_checks_needed.insert (*r);
388 /* don't increment n again - its the same list */
391 for (a = pending_adds.begin(); a != pending_adds.end(); ++a) {
392 dependent_checks_needed.insert (*a);
393 RegionAdded (*a); /* EMIT SIGNAL */
397 for (set<Region*>::iterator x = dependent_checks_needed.begin(); x != dependent_checks_needed.end(); ++x) {
398 check_dependents (**x, false);
401 for (r = pending_removals.begin(); r != pending_removals.end(); ++r) {
402 remove_dependents (**r);
403 RegionRemoved (*r); /* EMIT SIGNAL */
407 if ((freeze_length != _get_maximum_extent()) || pending_length) {
409 LengthChanged(); /* EMIT SIGNAL */
413 if (n || pending_modified) {
416 pending_modified = false;
417 Modified (); /* EMIT SIGNAL */
420 pending_adds.clear ();
421 pending_removals.clear ();
422 pending_bounds.clear ();
425 save_on_thaw = false;
426 save_state (last_save_reason);
432 /*************************************************************
434 *************************************************************/
437 Playlist::add_region (const Region& region, jack_nframes_t position, float times, bool with_save)
439 RegionLock rlock (this);
441 times = fabs (times);
443 int itimes = (int) floor (times);
445 jack_nframes_t pos = position;
448 add_region_internal (const_cast<Region*>(®ion), pos, true);
449 pos += region.length();
453 /* later regions will all be spliced anyway */
455 if (!holding_state ()) {
456 possibly_splice_unlocked ();
459 /* note that itimes can be zero if we being asked to just
460 insert a single fraction of the region.
463 for (int i = 0; i < itimes; ++i) {
464 Region *copy = createRegion (region);
465 add_region_internal (copy, pos, true);
466 pos += region.length();
469 if (floor (times) != times) {
470 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
472 _session.region_name (name, region.name(), false);
473 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
474 add_region_internal (sub, pos, true);
478 maybe_save_state (_("add region"));
483 Playlist::add_region_internal (Region *region, jack_nframes_t position, bool delay_sort)
485 RegionSortByPosition cmp;
486 jack_nframes_t old_length = 0;
488 // cerr << "adding region " << region->name() << " at " << position << endl;
490 if (!holding_state()) {
491 old_length = _get_maximum_extent();
494 region->set_playlist (this);
495 region->set_position (position, this);
496 region->lock_sources ();
498 timestamp_layer_op (*region);
500 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
502 if (!holding_state () && !in_set_state) {
503 /* layers get assigned from XML state */
507 /* we need to notify the existence of new region before checking dependents. Ick. */
509 notify_region_added (region);
511 if (!holding_state ()) {
512 check_dependents (*region, false);
513 if (old_length != _get_maximum_extent()) {
514 notify_length_changed ();
518 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy), region));
522 Playlist::replace_region (Region& old, Region& newr, jack_nframes_t pos)
524 RegionLock rlock (this);
526 remove_region_internal (&old);
527 add_region_internal (&newr, pos);
529 if (!holding_state ()) {
530 possibly_splice_unlocked ();
533 maybe_save_state (_("replace region"));
537 Playlist::remove_region (Region *region)
539 RegionLock rlock (this);
540 remove_region_internal (region);
542 if (!holding_state ()) {
543 possibly_splice_unlocked ();
546 maybe_save_state (_("remove region"));
550 Playlist::remove_region_internal (Region *region, bool delay_sort)
552 RegionList::iterator i;
553 jack_nframes_t old_length = 0;
555 // cerr << "removing region " << region->name() << endl;
557 if (!holding_state()) {
558 old_length = _get_maximum_extent();
561 for (i = regions.begin(); i != regions.end(); ++i) {
566 if (!holding_state ()) {
568 remove_dependents (*region);
570 if (old_length != _get_maximum_extent()) {
571 notify_length_changed ();
575 notify_region_removed (region);
583 Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level)
587 partition_internal (start, end, false, thawlist);
589 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
590 (*i)->thaw ("separation");
593 maybe_save_state (_("separate"));
597 Playlist::partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist)
599 RegionLock rlock (this);
603 RegionList::iterator tmp;
605 jack_nframes_t pos1, pos2, pos3, pos4;
606 RegionList new_regions;
610 /* need to work from a copy, because otherwise the regions we add during the process
611 get operated on as well.
614 RegionList copy = regions;
616 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
623 if (current->first_frame() == start && current->last_frame() == end) {
625 remove_region_internal (current);
630 if ((overlap = current->coverage (start, end)) == OverlapNone) {
634 pos1 = current->position();
637 pos4 = current->last_frame();
639 if (overlap == OverlapInternal) {
641 /* split: we need 3 new regions, the front, middle and end.
642 cut: we need 2 regions, the front and end.
647 ---------------*************************------------
650 ---------------*****++++++++++++++++====------------
652 ---------------*****----------------====------------
658 /* "middle" ++++++ */
660 _session.region_name (new_name, current->name(), false);
661 region = createRegion (*current, pos2 - pos1, pos3 - pos2, new_name,
662 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
663 add_region_internal (region, start, true);
664 new_regions.push_back (region);
669 _session.region_name (new_name, current->name(), false);
670 region = createRegion (*current, pos3 - pos1, pos4 - pos3, new_name,
671 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
673 add_region_internal (region, end, true);
674 new_regions.push_back (region);
679 thawlist.push_back (current);
680 current->trim_end (pos2, this);
682 } else if (overlap == OverlapEnd) {
686 ---------------*************************------------
689 ---------------**************+++++++++++------------
691 ---------------**************-----------------------
699 _session.region_name (new_name, current->name(), false);
700 region = createRegion (*current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
701 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
702 add_region_internal (region, start, true);
703 new_regions.push_back (region);
709 thawlist.push_back (current);
710 current->trim_end (pos2, this);
712 } else if (overlap == OverlapStart) {
714 /* split: we need 2 regions: the front and the end.
715 cut: just trim current to skip the cut area
720 ---------------*************************------------
724 ---------------****+++++++++++++++++++++------------
726 -------------------*********************------------
733 _session.region_name (new_name, current->name(), false);
734 region = createRegion (*current, 0, pos3 - pos1, new_name,
735 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
736 add_region_internal (region, pos1, true);
737 new_regions.push_back (region);
743 thawlist.push_back (current);
744 current->trim_front (pos3, this);
746 } else if (overlap == OverlapExternal) {
748 /* split: no split required.
749 cut: remove the region.
754 ---------------*************************------------
758 ---------------*************************------------
760 ----------------------------------------------------
765 remove_region_internal (current);
767 new_regions.push_back (current);
771 in_partition = false;
773 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
774 check_dependents (**i, false);
779 Playlist::cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
783 jack_nframes_t start;
785 if (ranges.empty()) {
789 start = ranges.front().start;
792 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
794 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
796 if (i == ranges.begin()) {
800 /* paste the next section into the nascent playlist,
801 offset to reflect the start of the first range we
805 ret->paste (*pl, (*i).start - start, 1.0f);
811 /* manually notify session of new playlist here
812 because the playlists were constructed without notifying
814 PlaylistCreated (ret);
821 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
823 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::cut;
824 return cut_copy (pmf, ranges, result_is_hidden);
828 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
830 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::copy;
831 return cut_copy (pmf, ranges, result_is_hidden);
835 Playlist::cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
841 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
842 string new_name = _name;
846 if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
850 partition_internal (start, start+cnt-1, true, thawlist);
853 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
854 (*i)->thaw ("playlist cut");
857 maybe_save_state (_("cut"));
863 Playlist::copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
867 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
868 string new_name = _name;
872 cnt = min (_get_maximum_extent() - start, cnt);
873 return copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
877 Playlist::paste (Playlist& other, jack_nframes_t position, float times)
879 times = fabs (times);
880 jack_nframes_t old_length;
883 RegionLock rl1 (this);
884 RegionLock rl2 (&other);
886 old_length = _get_maximum_extent();
888 int itimes = (int) floor (times);
889 jack_nframes_t pos = position;
890 jack_nframes_t shift = other._get_maximum_extent();
891 layer_t top_layer = regions.size();
894 for (RegionList::iterator i = other.regions.begin(); i != other.regions.end(); ++i) {
895 Region *copy_of_region = createRegion (**i);
897 /* put these new regions on top of all existing ones, but preserve
898 the ordering they had in the original playlist.
901 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
902 add_region_internal (copy_of_region, copy_of_region->position() + pos);
907 possibly_splice_unlocked ();
909 /* XXX shall we handle fractional cases at some point? */
911 if (old_length != _get_maximum_extent()) {
912 notify_length_changed ();
918 maybe_save_state (_("paste"));
925 Playlist::duplicate (Region& region, jack_nframes_t position, float times)
927 times = fabs (times);
929 RegionLock rl (this);
930 int itimes = (int) floor (times);
931 jack_nframes_t pos = position;
934 Region *copy = createRegion (region);
935 add_region_internal (copy, pos, true);
936 pos += region.length();
939 if (floor (times) != times) {
940 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
942 _session.region_name (name, region.name(), false);
943 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
944 add_region_internal (sub, pos, true);
947 maybe_save_state (_("duplicate"));
951 Playlist::split_region (Region& region, jack_nframes_t playlist_position)
953 RegionLock rl (this);
955 if (!region.covers (playlist_position)) {
959 if (region.position() == playlist_position ||
960 region.last_frame() == playlist_position) {
964 if (remove_region_internal (®ion, true)) {
970 jack_nframes_t before;
971 jack_nframes_t after;
975 before = playlist_position - region.position();
976 after = region.length() - before;
978 _session.region_name (before_name, region.name(), false);
979 left = createRegion (region, 0, before, before_name, region.layer(), Region::Flag (region.flags()|Region::LeftOfSplit));
981 _session.region_name (after_name, region.name(), false);
982 right = createRegion (region, before, after, after_name, region.layer(), Region::Flag (region.flags()|Region::RightOfSplit));
984 add_region_internal (left, region.position(), true);
985 add_region_internal (right, region.position() + before);
987 maybe_save_state (_("split"));
991 Playlist::possibly_splice ()
993 if (_edit_mode == Splice) {
999 Playlist::possibly_splice_unlocked ()
1001 if (_edit_mode == Splice) {
1007 Playlist::splice_locked ()
1010 RegionLock rl (this);
1014 notify_length_changed ();
1018 Playlist::splice_unlocked ()
1021 notify_length_changed ();
1025 Playlist::core_splice ()
1029 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1031 RegionList::iterator next;
1036 if (next == regions.end()) {
1040 (*next)->set_position ((*i)->last_frame() + 1, this);
1047 Playlist::region_bounds_changed (Change what_changed, Region *region)
1049 if (in_set_state || _splicing || _nudging) {
1053 if (what_changed & ARDOUR::PositionChanged) {
1055 /* remove it from the list then add it back in
1056 the right place again.
1059 RegionSortByPosition cmp;
1061 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1063 if (i == regions.end()) {
1064 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1065 _name, region->name())
1071 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp),
1076 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1078 if (holding_state ()) {
1079 pending_bounds.push_back (region);
1081 if (_session.get_layer_model() == Session::MoveAddHigher) {
1082 /* it moved or changed length, so change the timestamp */
1083 timestamp_layer_op (*region);
1087 check_dependents (*region, false);
1088 notify_length_changed ();
1095 Playlist::region_changed_proxy (Change what_changed, Region* region)
1097 /* this makes a virtual call to the right kind of playlist ... */
1099 region_changed (what_changed, region);
1103 Playlist::region_changed (Change what_changed, Region* region)
1105 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1108 if (in_set_state || in_flush) {
1113 if (what_changed & BoundsChanged) {
1114 region_bounds_changed (what_changed, region);
1115 save = !(_splicing || _nudging);
1118 if ((what_changed & Region::MuteChanged) &&
1119 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1120 check_dependents (*region, false);
1123 if (what_changed & our_interests) {
1132 Playlist::clear (bool with_delete, bool with_save)
1134 RegionList::iterator i;
1138 RegionLock rl (this);
1143 for (i = tmp.begin(); i != tmp.end(); ++i) {
1144 notify_region_removed (*i);
1151 maybe_save_state (_("clear"));
1155 /***********************************************************************
1157 **********************************************************************/
1159 Playlist::RegionList *
1160 Playlist::regions_at (jack_nframes_t frame)
1163 RegionLock rlock (this);
1164 return find_regions_at (frame);
1168 Playlist::top_region_at (jack_nframes_t frame)
1171 RegionLock rlock (this);
1172 RegionList *rlist = find_regions_at (frame);
1175 if (rlist->size()) {
1176 RegionSortByLayer cmp;
1178 region = rlist->back();
1185 Playlist::RegionList *
1186 Playlist::find_regions_at (jack_nframes_t frame)
1188 RegionList *rlist = new RegionList;
1190 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1191 if ((*i)->covers (frame)) {
1192 rlist->push_back (*i);
1199 Playlist::RegionList *
1200 Playlist::regions_touched (jack_nframes_t start, jack_nframes_t end)
1202 RegionLock rlock (this);
1203 RegionList *rlist = new RegionList;
1205 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1206 if ((*i)->coverage (start, end) != OverlapNone) {
1207 rlist->push_back (*i);
1217 Playlist::find_next_region (jack_nframes_t frame, RegionPoint point, int dir)
1219 RegionLock rlock (this);
1221 jack_nframes_t closest = max_frames;
1223 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1225 jack_nframes_t distance;
1227 jack_nframes_t pos = 0;
1231 pos = r->first_frame ();
1234 pos = r->last_frame ();
1237 pos = r->adjust_to_sync (r->first_frame());
1242 case 1: /* forwards */
1245 if ((distance = pos - frame) < closest) {
1253 default: /* backwards */
1256 if ((distance = frame - pos) < closest) {
1268 /***********************************************************************/
1273 Playlist::mark_session_dirty ()
1275 if (!in_set_state && !holding_state ()) {
1276 _session.set_dirty();
1281 Playlist::set_state (const XMLNode& node)
1283 in_set_state = true;
1287 XMLNodeConstIterator niter;
1288 XMLPropertyList plist;
1289 XMLPropertyConstIterator piter;
1294 clear (false, false);
1296 if (node.name() != "Playlist") {
1297 in_set_state = false;
1301 plist = node.properties();
1303 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1307 if (prop->name() == X_("name")) {
1308 _name = prop->value();
1309 } else if (prop->name() == X_("orig_diskstream_id")) {
1310 sscanf (prop->value().c_str(), "%" PRIu64, &_orig_diskstream_id);
1311 } else if (prop->name() == X_("frozen")) {
1312 _frozen = (prop->value() == X_("yes"));
1316 nlist = node.children();
1318 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1322 if (child->name() == "Region") {
1324 if ((region = createRegion (_session, *child, true)) == 0) {
1325 error << _("Playlist: cannot create region from state file") << endmsg;
1329 add_region (*region, region->position(), 1.0, false);
1334 /* update dependents, which was not done during add_region_internal
1335 due to in_set_state being true
1338 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1339 check_dependents (**r, false);
1342 in_set_state = false;
1348 Playlist::get_state()
1354 Playlist::get_template()
1356 return state(false);
1360 Playlist::state (bool full_state)
1362 XMLNode *node = new XMLNode (X_("Playlist"));
1365 node->add_property (X_("name"), _name);
1367 snprintf (buf, sizeof(buf), "%" PRIu64, _orig_diskstream_id);
1368 node->add_property (X_("orig_diskstream_id"), buf);
1369 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1372 RegionLock rlock (this, false);
1374 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1375 node->add_child_nocopy ((*i)->get_state());
1380 node->add_child_copy (*_extra_xml);
1387 Playlist::empty() const
1389 return regions.empty();
1393 Playlist::get_maximum_extent () const
1395 RegionLock rlock (const_cast<Playlist *>(this));
1396 return _get_maximum_extent ();
1400 Playlist::_get_maximum_extent () const
1402 RegionList::const_iterator i;
1403 jack_nframes_t max_extent = 0;
1404 jack_nframes_t end = 0;
1406 for (i = regions.begin(); i != regions.end(); ++i) {
1407 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1416 Playlist::bump_name (string name, Session &session)
1418 string newname = name;
1421 newname = Playlist::bump_name_once (newname);
1422 } while (session.playlist_by_name(newname)!=NULL);
1428 Playlist::bump_name_once (string name)
1430 string::size_type period;
1433 if ((period = name.find_last_of ('.')) == string::npos) {
1440 sscanf (name.substr (period+1).c_str(), "%d", &version);
1441 snprintf (buf, sizeof(buf), "%d", version+1);
1443 newname = name.substr (0, period+1);
1451 Playlist::top_layer() const
1453 RegionLock rlock (const_cast<Playlist *> (this));
1456 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1457 top = max (top, (*i)->layer());
1463 Playlist::set_edit_mode (EditMode mode)
1468 /********************
1470 ********************/
1473 Playlist::relayer ()
1475 RegionList::iterator i;
1478 /* don't send multiple Modified notifications
1479 when multiple regions are relayered.
1484 if (_session.get_layer_model() == Session::MoveAddHigher ||
1485 _session.get_layer_model() == Session::AddHigher) {
1487 RegionSortByLastLayerOp cmp;
1488 RegionList copy = regions;
1492 for (i = copy.begin(); i != copy.end(); ++i) {
1493 (*i)->set_layer (layer++);
1498 /* Session::LaterHigher model */
1500 for (i = regions.begin(); i != regions.end(); ++i) {
1501 (*i)->set_layer (layer++);
1505 /* sending Modified means that various kinds of layering
1506 models operate correctly at the GUI
1507 level. slightly inefficient, but only slightly.
1509 We force a Modified signal here in case no layers actually
1518 /* XXX these layer functions are all deprecated */
1521 Playlist::raise_region (Region& region)
1523 uint32_t rsz = regions.size();
1524 layer_t target = region.layer() + 1U;
1526 if (target >= rsz) {
1527 /* its already at the effective top */
1531 move_region_to_layer (target, region, 1);
1535 Playlist::lower_region (Region& region)
1537 if (region.layer() == 0) {
1538 /* its already at the bottom */
1542 layer_t target = region.layer() - 1U;
1544 move_region_to_layer (target, region, -1);
1548 Playlist::raise_region_to_top (Region& region)
1550 /* does nothing useful if layering mode is later=higher */
1551 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1552 (_session.get_layer_model() == Session::AddHigher)) {
1553 timestamp_layer_op (region);
1559 Playlist::lower_region_to_bottom (Region& region)
1561 /* does nothing useful if layering mode is later=higher */
1562 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1563 (_session.get_layer_model() == Session::AddHigher)) {
1564 region.set_last_layer_op (0);
1570 Playlist::move_region_to_layer (layer_t target_layer, Region& region, int dir)
1572 RegionList::iterator i;
1573 typedef pair<Region*,layer_t> LayerInfo;
1574 list<LayerInfo> layerinfo;
1578 RegionLock rlock (const_cast<Playlist *> (this));
1580 for (i = regions.begin(); i != regions.end(); ++i) {
1582 if (®ion == *i) {
1588 /* region is moving up, move all regions on intermediate layers
1592 if ((*i)->layer() > region.layer() && (*i)->layer() <= target_layer) {
1593 dest = (*i)->layer() - 1;
1600 /* region is moving down, move all regions on intermediate layers
1604 if ((*i)->layer() < region.layer() && (*i)->layer() >= target_layer) {
1605 dest = (*i)->layer() + 1;
1615 newpair.second = dest;
1617 layerinfo.push_back (newpair);
1621 /* now reset the layers without holding the region lock */
1623 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1624 x->first->set_layer (x->second);
1627 region.set_layer (target_layer);
1629 /* now check all dependents */
1631 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1632 check_dependents (*(x->first), false);
1635 check_dependents (region, false);
1641 Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards)
1643 RegionList::iterator i;
1644 jack_nframes_t new_pos;
1650 RegionLock rlock (const_cast<Playlist *> (this));
1652 for (i = regions.begin(); i != regions.end(); ++i) {
1654 if ((*i)->position() >= start) {
1658 if ((*i)->last_frame() > max_frames - distance) {
1659 new_pos = max_frames - (*i)->length();
1661 new_pos = (*i)->position() + distance;
1666 if ((*i)->position() > distance) {
1667 new_pos = (*i)->position() - distance;
1673 (*i)->set_position (new_pos, this);
1681 maybe_save_state (_("nudged"));
1682 notify_length_changed ();
1688 Playlist::find_region (id_t id) const
1690 RegionLock rlock (const_cast<Playlist*> (this));
1691 RegionList::const_iterator i;
1693 for (i = regions.begin(); i != regions.end(); ++i) {
1694 if ((*i)->id() == id) {
1703 Playlist::save_state (std::string why)
1705 if (!in_set_state) {
1706 StateManager::save_state (why);
1711 Playlist::dump () const
1715 cerr << "Playlist \"" << _name << "\" " << endl
1716 << regions.size() << " regions "
1719 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1721 cerr << " " << r->name() << " ["
1722 << r->start() << "+" << r->length()
1732 Playlist::set_frozen (bool yn)
1738 Playlist::timestamp_layer_op (Region& region)
1740 // struct timeval tv;
1741 // gettimeofday (&tv, 0);
1742 region.set_last_layer_op (++layer_op_counter);
1746 Playlist::maybe_save_state (string why)
1748 if (holding_state ()) {
1749 save_on_thaw = true;
1750 last_save_reason = why;