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)
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 atomic_set (&block_notifications, 0);
229 atomic_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 atomic_inc (&ignore_state_changes);
301 atomic_dec (&ignore_state_changes);
302 release_notifications ();
307 Playlist::delay_notifications ()
309 atomic_inc (&block_notifications);
310 freeze_length = _get_maximum_extent();
314 Playlist::release_notifications ()
316 if (atomic_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) {
985 if (remove_region_internal (®ion, true)) {
991 jack_nframes_t before;
992 jack_nframes_t after;
996 before = playlist_position - region.position();
997 after = region.length() - before;
999 _session.region_name (before_name, region.name(), false);
1000 left = createRegion (region, 0, before, before_name, region.layer(), Region::Flag (region.flags()|Region::LeftOfSplit));
1002 _session.region_name (after_name, region.name(), false);
1003 right = createRegion (region, before, after, after_name, region.layer(), Region::Flag (region.flags()|Region::RightOfSplit));
1005 add_region_internal (left, region.position(), true);
1006 add_region_internal (right, region.position() + before);
1008 maybe_save_state (_("split"));
1012 Playlist::possibly_splice ()
1014 if (_edit_mode == Splice) {
1020 Playlist::possibly_splice_unlocked ()
1022 if (_edit_mode == Splice) {
1028 Playlist::splice_locked ()
1031 RegionLock rl (this);
1035 notify_length_changed ();
1039 Playlist::splice_unlocked ()
1042 notify_length_changed ();
1046 Playlist::core_splice ()
1050 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1052 RegionList::iterator next;
1057 if (next == regions.end()) {
1061 (*next)->set_position ((*i)->last_frame() + 1, this);
1068 Playlist::region_bounds_changed (Change what_changed, Region *region)
1070 if (in_set_state || _splicing || _nudging) {
1074 if (what_changed & ARDOUR::PositionChanged) {
1076 /* remove it from the list then add it back in
1077 the right place again.
1080 RegionSortByPosition cmp;
1082 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1084 if (i == regions.end()) {
1085 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1086 _name, region->name())
1092 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp),
1097 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1099 if (holding_state ()) {
1100 pending_bounds.push_back (region);
1102 if (_session.get_layer_model() == Session::MoveAddHigher) {
1103 /* it moved or changed length, so change the timestamp */
1104 timestamp_layer_op (*region);
1108 check_dependents (*region, false);
1109 notify_length_changed ();
1116 Playlist::region_changed_proxy (Change what_changed, Region* region)
1118 /* this makes a virtual call to the right kind of playlist ... */
1120 region_changed (what_changed, region);
1124 Playlist::region_changed (Change what_changed, Region* region)
1126 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1129 if (in_set_state || in_flush) {
1134 if (what_changed & BoundsChanged) {
1135 region_bounds_changed (what_changed, region);
1136 save = !(_splicing || _nudging);
1139 if ((what_changed & Region::MuteChanged) &&
1140 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1141 check_dependents (*region, false);
1144 if (what_changed & our_interests) {
1153 Playlist::clear (bool with_delete, bool with_save)
1155 RegionList::iterator i;
1159 RegionLock rl (this);
1164 for (i = tmp.begin(); i != tmp.end(); ++i) {
1165 notify_region_removed (*i);
1172 maybe_save_state (_("clear"));
1176 /***********************************************************************
1178 **********************************************************************/
1180 Playlist::RegionList *
1181 Playlist::regions_at (jack_nframes_t frame)
1184 RegionLock rlock (this);
1185 return find_regions_at (frame);
1189 Playlist::top_region_at (jack_nframes_t frame)
1192 RegionLock rlock (this);
1193 RegionList *rlist = find_regions_at (frame);
1196 if (rlist->size()) {
1197 RegionSortByLayer cmp;
1199 region = rlist->back();
1206 Playlist::RegionList *
1207 Playlist::find_regions_at (jack_nframes_t frame)
1209 RegionList *rlist = new RegionList;
1211 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1212 if ((*i)->covers (frame)) {
1213 rlist->push_back (*i);
1220 Playlist::RegionList *
1221 Playlist::regions_touched (jack_nframes_t start, jack_nframes_t end)
1223 RegionLock rlock (this);
1224 RegionList *rlist = new RegionList;
1226 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1227 if ((*i)->coverage (start, end) != OverlapNone) {
1228 rlist->push_back (*i);
1238 Playlist::find_next_region (jack_nframes_t frame, RegionPoint point, int dir)
1240 RegionLock rlock (this);
1242 jack_nframes_t closest = max_frames;
1244 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1246 jack_nframes_t distance;
1248 jack_nframes_t pos = 0;
1252 pos = r->first_frame ();
1255 pos = r->last_frame ();
1258 pos = r->adjust_to_sync (r->first_frame());
1263 case 1: /* forwards */
1266 if ((distance = pos - frame) < closest) {
1274 default: /* backwards */
1277 if ((distance = frame - pos) < closest) {
1289 /***********************************************************************/
1294 Playlist::mark_session_dirty ()
1296 if (!in_set_state && !holding_state ()) {
1297 _session.set_dirty();
1302 Playlist::set_state (const XMLNode& node)
1304 in_set_state = true;
1308 XMLNodeConstIterator niter;
1309 XMLPropertyList plist;
1310 XMLPropertyConstIterator piter;
1315 clear (false, false);
1317 if (node.name() != "Playlist") {
1318 in_set_state = false;
1322 plist = node.properties();
1324 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1328 if (prop->name() == X_("name")) {
1329 _name = prop->value();
1330 } else if (prop->name() == X_("orig_diskstream_id")) {
1331 sscanf (prop->value().c_str(), "%" PRIu64, &_orig_diskstream_id);
1332 } else if (prop->name() == X_("frozen")) {
1333 _frozen = (prop->value() == X_("yes"));
1337 nlist = node.children();
1339 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1343 if (child->name() == "Region") {
1345 if ((region = createRegion (_session, *child, true)) == 0) {
1346 error << _("Playlist: cannot create region from state file") << endmsg;
1350 add_region (*region, region->position(), 1.0, false);
1352 // So that layer_op ordering doesn't get screwed up
1353 region->set_last_layer_op( region->layer());
1359 /* update dependents, which was not done during add_region_internal
1360 due to in_set_state being true
1363 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1364 check_dependents (**r, false);
1367 in_set_state = false;
1373 Playlist::get_state()
1379 Playlist::get_template()
1381 return state(false);
1385 Playlist::state (bool full_state)
1387 XMLNode *node = new XMLNode (X_("Playlist"));
1390 node->add_property (X_("name"), _name);
1392 snprintf (buf, sizeof(buf), "%" PRIu64, _orig_diskstream_id);
1393 node->add_property (X_("orig_diskstream_id"), buf);
1394 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1397 RegionLock rlock (this, false);
1399 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1400 node->add_child_nocopy ((*i)->get_state());
1405 node->add_child_copy (*_extra_xml);
1412 Playlist::empty() const
1414 return regions.empty();
1418 Playlist::get_maximum_extent () const
1420 RegionLock rlock (const_cast<Playlist *>(this));
1421 return _get_maximum_extent ();
1425 Playlist::_get_maximum_extent () const
1427 RegionList::const_iterator i;
1428 jack_nframes_t max_extent = 0;
1429 jack_nframes_t end = 0;
1431 for (i = regions.begin(); i != regions.end(); ++i) {
1432 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1441 Playlist::bump_name (string name, Session &session)
1443 string newname = name;
1446 newname = Playlist::bump_name_once (newname);
1447 } while (session.playlist_by_name(newname)!=NULL);
1453 Playlist::bump_name_once (string name)
1455 string::size_type period;
1458 if ((period = name.find_last_of ('.')) == string::npos) {
1465 sscanf (name.substr (period+1).c_str(), "%d", &version);
1466 snprintf (buf, sizeof(buf), "%d", version+1);
1468 newname = name.substr (0, period+1);
1476 Playlist::top_layer() const
1478 RegionLock rlock (const_cast<Playlist *> (this));
1481 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1482 top = max (top, (*i)->layer());
1488 Playlist::set_edit_mode (EditMode mode)
1493 /********************
1495 ********************/
1498 Playlist::relayer ()
1500 RegionList::iterator i;
1503 /* don't send multiple Modified notifications
1504 when multiple regions are relayered.
1509 if (_session.get_layer_model() == Session::MoveAddHigher ||
1510 _session.get_layer_model() == Session::AddHigher) {
1512 RegionSortByLastLayerOp cmp;
1513 RegionList copy = regions;
1517 for (i = copy.begin(); i != copy.end(); ++i) {
1518 (*i)->set_layer (layer++);
1523 /* Session::LaterHigher model */
1525 for (i = regions.begin(); i != regions.end(); ++i) {
1526 (*i)->set_layer (layer++);
1530 /* sending Modified means that various kinds of layering
1531 models operate correctly at the GUI
1532 level. slightly inefficient, but only slightly.
1534 We force a Modified signal here in case no layers actually
1543 /* XXX these layer functions are all deprecated */
1546 Playlist::raise_region (Region& region)
1548 uint32_t rsz = regions.size();
1549 layer_t target = region.layer() + 1U;
1551 if (target >= rsz) {
1552 /* its already at the effective top */
1556 move_region_to_layer (target, region, 1);
1560 Playlist::lower_region (Region& region)
1562 if (region.layer() == 0) {
1563 /* its already at the bottom */
1567 layer_t target = region.layer() - 1U;
1569 move_region_to_layer (target, region, -1);
1573 Playlist::raise_region_to_top (Region& region)
1575 /* does nothing useful if layering mode is later=higher */
1576 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1577 (_session.get_layer_model() == Session::AddHigher)) {
1578 timestamp_layer_op (region);
1584 Playlist::lower_region_to_bottom (Region& region)
1586 /* does nothing useful if layering mode is later=higher */
1587 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1588 (_session.get_layer_model() == Session::AddHigher)) {
1589 region.set_last_layer_op (0);
1595 Playlist::move_region_to_layer (layer_t target_layer, Region& region, int dir)
1597 RegionList::iterator i;
1598 typedef pair<Region*,layer_t> LayerInfo;
1599 list<LayerInfo> layerinfo;
1603 RegionLock rlock (const_cast<Playlist *> (this));
1605 for (i = regions.begin(); i != regions.end(); ++i) {
1607 if (®ion == *i) {
1613 /* region is moving up, move all regions on intermediate layers
1617 if ((*i)->layer() > region.layer() && (*i)->layer() <= target_layer) {
1618 dest = (*i)->layer() - 1;
1625 /* region is moving down, move all regions on intermediate layers
1629 if ((*i)->layer() < region.layer() && (*i)->layer() >= target_layer) {
1630 dest = (*i)->layer() + 1;
1640 newpair.second = dest;
1642 layerinfo.push_back (newpair);
1646 /* now reset the layers without holding the region lock */
1648 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1649 x->first->set_layer (x->second);
1652 region.set_layer (target_layer);
1654 /* now check all dependents */
1656 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1657 check_dependents (*(x->first), false);
1660 check_dependents (region, false);
1666 Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards)
1668 RegionList::iterator i;
1669 jack_nframes_t new_pos;
1675 RegionLock rlock (const_cast<Playlist *> (this));
1677 for (i = regions.begin(); i != regions.end(); ++i) {
1679 if ((*i)->position() >= start) {
1683 if ((*i)->last_frame() > max_frames - distance) {
1684 new_pos = max_frames - (*i)->length();
1686 new_pos = (*i)->position() + distance;
1691 if ((*i)->position() > distance) {
1692 new_pos = (*i)->position() - distance;
1698 (*i)->set_position (new_pos, this);
1706 maybe_save_state (_("nudged"));
1707 notify_length_changed ();
1713 Playlist::find_region (id_t id) const
1715 RegionLock rlock (const_cast<Playlist*> (this));
1716 RegionList::const_iterator i;
1718 for (i = regions.begin(); i != regions.end(); ++i) {
1719 if ((*i)->id() == id) {
1728 Playlist::save_state (std::string why)
1730 if (!in_set_state) {
1731 StateManager::save_state (why);
1736 Playlist::dump () const
1740 cerr << "Playlist \"" << _name << "\" " << endl
1741 << regions.size() << " regions "
1744 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1746 cerr << " " << r->name() << " ["
1747 << r->start() << "+" << r->length()
1757 Playlist::set_frozen (bool yn)
1763 Playlist::timestamp_layer_op (Region& region)
1765 // struct timeval tv;
1766 // gettimeofday (&tv, 0);
1767 region.set_last_layer_op (++layer_op_counter);
1771 Playlist::maybe_save_state (string why)
1773 if (holding_state ()) {
1774 save_on_thaw = true;
1775 last_save_reason = why;