2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <sigc++/bind.h>
31 #include <pbd/failed_constructor.h>
32 #include <pbd/stl_delete.h>
33 #include <pbd/xml++.h>
35 #include <ardour/playlist.h>
36 #include <ardour/session.h>
37 #include <ardour/region.h>
38 #include <ardour/region_factory.h>
43 using namespace ARDOUR;
46 sigc::signal<void,Playlist*> Playlist::PlaylistCreated;
48 struct ShowMeTheList {
49 ShowMeTheList (Playlist *pl, const string& n) : playlist (pl), name (n) {}
51 cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
57 struct RegionSortByLayer {
58 bool operator() (Region *a, Region *b) {
59 return a->layer() < b->layer();
63 struct RegionSortByPosition {
64 bool operator() (Region *a, Region *b) {
65 return a->position() < b->position();
69 struct RegionSortByLastLayerOp {
70 bool operator() (Region *a, Region *b) {
71 return a->last_layer_op() < b->last_layer_op();
75 Playlist::Playlist (Session& sess, string nom, bool hide)
83 Playlist::Playlist (Session& sess, const XMLNode& node, bool hide)
87 _name = "unnamed"; /* reset by set_state */
89 if (set_state (node)) {
90 throw failed_constructor();
94 Playlist::Playlist (const Playlist& other, string namestr, bool hide)
95 : _name (namestr), _session (other._session), _orig_diskstream_id(other._orig_diskstream_id)
100 other.copy_regions (tmp);
104 for (list<Region*>::iterator x = tmp.begin(); x != tmp.end(); ++x) {
105 add_region_internal( (*x), (*x)->position() );
108 in_set_state = false;
110 _splicing = other._splicing;
111 _nudging = other._nudging;
112 _edit_mode = other._edit_mode;
114 in_set_state = false;
116 in_partition = false;
118 _read_data_count = 0;
119 _frozen = other._frozen;
120 save_on_thaw = false;
122 layer_op_counter = other.layer_op_counter;
123 freeze_length = other.freeze_length;
127 Playlist::Playlist (const Playlist& other, jack_nframes_t start, jack_nframes_t cnt, string str, bool hide)
128 : _name (str), _session (other._session), _orig_diskstream_id(other._orig_diskstream_id)
130 RegionLock rlock2 (&((Playlist&)other));
132 jack_nframes_t end = start + cnt - 1;
136 for (RegionList::const_iterator i = other.regions.begin(); i != other.regions.end(); i++) {
140 jack_nframes_t offset = 0;
141 jack_nframes_t position = 0;
142 jack_nframes_t len = 0;
148 overlap = region->coverage (start, end);
154 case OverlapInternal:
155 offset = start - region->position();
162 position = region->position() - start;
163 len = end - region->position();
167 offset = start - region->position();
169 len = region->length() - offset;
172 case OverlapExternal:
174 position = region->position() - start;
175 len = region->length();
179 _session.region_name (new_name, region->name(), false);
181 new_region = createRegion (*region, offset, len, new_name, region->layer(), region->flags());
183 add_region_internal (new_region, position, true);
186 /* this constructor does NOT notify others (session) */
193 InUse (this, true); /* EMIT SIGNAL */
203 InUse (this, false); /* EMIT SIGNAL */
206 /* nobody knows we exist */
214 Playlist::copy_regions (RegionList& newlist) const
216 RegionLock rlock (const_cast<Playlist *> (this));
218 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
219 newlist.push_back (createRegion (**i));
224 Playlist::init (bool hide)
226 g_atomic_int_set (&block_notifications, 0);
227 g_atomic_int_set (&ignore_state_changes, 0);
228 pending_modified = false;
229 pending_length = false;
234 in_set_state = false;
235 _edit_mode = _session.get_edit_mode();
237 in_partition = false;
239 _read_data_count = 0;
241 save_on_thaw = false;
242 layer_op_counter = 0;
245 Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty));
248 Playlist::Playlist (const Playlist& pl)
249 : _session (pl._session)
251 fatal << _("playlist const copy constructor called") << endmsg;
254 Playlist::Playlist (Playlist& pl)
255 : _session (pl._session)
257 fatal << _("playlist non-const copy constructor called") << endmsg;
260 Playlist::~Playlist ()
265 Playlist::set_name (const string& str)
267 /* in a typical situation, a playlist is being used
268 by one diskstream and also is referenced by the
269 Session. if there are more references than that,
270 then don't change the name.
278 NameChanged(); /* EMIT SIGNAL */
281 /***********************************************************************
282 CHANGE NOTIFICATION HANDLING
284 Notifications must be delayed till the region_lock is released. This
285 is necessary because handlers for the signals may need to acquire
286 the lock (e.g. to read from the playlist).
287 ***********************************************************************/
292 delay_notifications ();
293 g_atomic_int_inc (&ignore_state_changes);
299 g_atomic_int_dec_and_test (&ignore_state_changes);
300 release_notifications ();
305 Playlist::delay_notifications ()
307 g_atomic_int_inc (&block_notifications);
308 freeze_length = _get_maximum_extent();
312 Playlist::release_notifications ()
314 if (g_atomic_int_dec_and_test (&block_notifications)) {
315 flush_notifications ();
321 Playlist::notify_modified ()
323 if (holding_state ()) {
324 pending_modified = true;
326 pending_modified = false;
327 Modified(); /* EMIT SIGNAL */
332 Playlist::notify_region_removed (Region *r)
334 if (holding_state ()) {
335 pending_removals.insert (pending_removals.end(), r);
337 RegionRemoved (r); /* EMIT SIGNAL */
338 /* this might not be true, but we have to act
339 as though it could be.
341 LengthChanged (); /* EMIT SIGNAL */
342 Modified (); /* EMIT SIGNAL */
347 Playlist::notify_region_added (Region *r)
349 if (holding_state()) {
350 pending_adds.insert (pending_adds.end(), r);
352 RegionAdded (r); /* EMIT SIGNAL */
353 /* this might not be true, but we have to act
354 as though it could be.
356 LengthChanged (); /* EMIT SIGNAL */
357 Modified (); /* EMIT SIGNAL */
362 Playlist::notify_length_changed ()
364 if (holding_state ()) {
365 pending_length = true;
367 LengthChanged(); /* EMIT SIGNAL */
368 Modified (); /* EMIT SIGNAL */
373 Playlist::flush_notifications ()
375 RegionList::iterator r;
376 RegionList::iterator a;
377 set<Region*> dependent_checks_needed;
386 /* we have no idea what order the regions ended up in pending
387 bounds (it could be based on selection order, for example).
388 so, to preserve layering in the "most recently moved is higher"
389 model, sort them by existing layer, then timestamp them.
392 // RegionSortByLayer cmp;
393 // pending_bounds.sort (cmp);
395 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
396 if (_session.get_layer_model() == Session::MoveAddHigher) {
397 timestamp_layer_op (**r);
399 pending_length = true;
403 for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
404 dependent_checks_needed.insert (*r);
405 /* don't increment n again - its the same list */
408 for (a = pending_adds.begin(); a != pending_adds.end(); ++a) {
409 dependent_checks_needed.insert (*a);
410 RegionAdded (*a); /* EMIT SIGNAL */
414 for (set<Region*>::iterator x = dependent_checks_needed.begin(); x != dependent_checks_needed.end(); ++x) {
415 check_dependents (**x, false);
418 for (r = pending_removals.begin(); r != pending_removals.end(); ++r) {
419 remove_dependents (**r);
420 RegionRemoved (*r); /* EMIT SIGNAL */
424 if ((freeze_length != _get_maximum_extent()) || pending_length) {
426 LengthChanged(); /* EMIT SIGNAL */
430 if (n || pending_modified) {
435 pending_modified = false;
436 Modified (); /* EMIT SIGNAL */
439 pending_adds.clear ();
440 pending_removals.clear ();
441 pending_bounds.clear ();
444 save_on_thaw = false;
445 save_state (last_save_reason);
451 /*************************************************************
453 *************************************************************/
456 Playlist::add_region (const Region& region, jack_nframes_t position, float times, bool with_save)
458 RegionLock rlock (this);
460 times = fabs (times);
462 int itimes = (int) floor (times);
464 jack_nframes_t pos = position;
467 add_region_internal (const_cast<Region*>(®ion), pos, true);
468 pos += region.length();
472 /* later regions will all be spliced anyway */
474 if (!holding_state ()) {
475 possibly_splice_unlocked ();
478 /* note that itimes can be zero if we being asked to just
479 insert a single fraction of the region.
482 for (int i = 0; i < itimes; ++i) {
483 Region *copy = createRegion (region);
484 add_region_internal (copy, pos, true);
485 pos += region.length();
488 if (floor (times) != times) {
489 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
491 _session.region_name (name, region.name(), false);
492 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
493 add_region_internal (sub, pos, true);
497 maybe_save_state (_("add region"));
502 Playlist::add_region_internal (Region *region, jack_nframes_t position, bool delay_sort)
504 RegionSortByPosition cmp;
505 jack_nframes_t old_length = 0;
507 // cerr << "adding region " << region->name() << " at " << position << endl;
509 if (!holding_state()) {
510 old_length = _get_maximum_extent();
513 region->set_playlist (this);
514 region->set_position (position, this);
515 region->lock_sources ();
517 timestamp_layer_op (*region);
519 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
521 if (!holding_state () && !in_set_state) {
522 /* layers get assigned from XML state */
526 /* we need to notify the existence of new region before checking dependents. Ick. */
528 notify_region_added (region);
530 if (!holding_state ()) {
531 check_dependents (*region, false);
532 if (old_length != _get_maximum_extent()) {
533 notify_length_changed ();
537 region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy), region));
541 Playlist::replace_region (Region& old, Region& newr, jack_nframes_t pos)
543 RegionLock rlock (this);
545 remove_region_internal (&old);
546 add_region_internal (&newr, pos);
548 if (!holding_state ()) {
549 possibly_splice_unlocked ();
552 maybe_save_state (_("replace region"));
556 Playlist::remove_region (Region *region)
558 RegionLock rlock (this);
559 remove_region_internal (region);
561 if (!holding_state ()) {
562 possibly_splice_unlocked ();
565 maybe_save_state (_("remove region"));
569 Playlist::remove_region_internal (Region *region, bool delay_sort)
571 RegionList::iterator i;
572 jack_nframes_t old_length = 0;
574 // cerr << "removing region " << region->name() << endl;
576 if (!holding_state()) {
577 old_length = _get_maximum_extent();
580 for (i = regions.begin(); i != regions.end(); ++i) {
585 if (!holding_state ()) {
587 remove_dependents (*region);
589 if (old_length != _get_maximum_extent()) {
590 notify_length_changed ();
594 notify_region_removed (region);
602 Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level)
606 partition_internal (start, end, false, thawlist);
608 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
609 (*i)->thaw ("separation");
612 maybe_save_state (_("separate"));
616 Playlist::partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist)
618 RegionLock rlock (this);
622 RegionList::iterator tmp;
624 jack_nframes_t pos1, pos2, pos3, pos4;
625 RegionList new_regions;
629 /* need to work from a copy, because otherwise the regions we add during the process
630 get operated on as well.
633 RegionList copy = regions;
635 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
642 if (current->first_frame() == start && current->last_frame() == end) {
644 remove_region_internal (current);
649 if ((overlap = current->coverage (start, end)) == OverlapNone) {
653 pos1 = current->position();
656 pos4 = current->last_frame();
658 if (overlap == OverlapInternal) {
660 /* split: we need 3 new regions, the front, middle and end.
661 cut: we need 2 regions, the front and end.
666 ---------------*************************------------
669 ---------------*****++++++++++++++++====------------
671 ---------------*****----------------====------------
677 /* "middle" ++++++ */
679 _session.region_name (new_name, current->name(), false);
680 region = createRegion (*current, pos2 - pos1, pos3 - pos2, new_name,
681 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
682 add_region_internal (region, start, true);
683 new_regions.push_back (region);
688 _session.region_name (new_name, current->name(), false);
689 region = createRegion (*current, pos3 - pos1, pos4 - pos3, new_name,
690 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
692 add_region_internal (region, end, true);
693 new_regions.push_back (region);
698 thawlist.push_back (current);
699 current->trim_end (pos2, this);
701 } else if (overlap == OverlapEnd) {
705 ---------------*************************------------
708 ---------------**************+++++++++++------------
710 ---------------**************-----------------------
718 _session.region_name (new_name, current->name(), false);
719 region = createRegion (*current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
720 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
721 add_region_internal (region, start, true);
722 new_regions.push_back (region);
728 thawlist.push_back (current);
729 current->trim_end (pos2, this);
731 } else if (overlap == OverlapStart) {
733 /* split: we need 2 regions: the front and the end.
734 cut: just trim current to skip the cut area
739 ---------------*************************------------
743 ---------------****+++++++++++++++++++++------------
745 -------------------*********************------------
752 _session.region_name (new_name, current->name(), false);
753 region = createRegion (*current, 0, pos3 - pos1, new_name,
754 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
755 add_region_internal (region, pos1, true);
756 new_regions.push_back (region);
762 thawlist.push_back (current);
763 current->trim_front (pos3, this);
765 } else if (overlap == OverlapExternal) {
767 /* split: no split required.
768 cut: remove the region.
773 ---------------*************************------------
777 ---------------*************************------------
779 ----------------------------------------------------
784 remove_region_internal (current);
786 new_regions.push_back (current);
790 in_partition = false;
792 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
793 check_dependents (**i, false);
798 Playlist::cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
802 jack_nframes_t start;
804 if (ranges.empty()) {
808 start = ranges.front().start;
811 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
813 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
815 if (i == ranges.begin()) {
819 /* paste the next section into the nascent playlist,
820 offset to reflect the start of the first range we
824 ret->paste (*pl, (*i).start - start, 1.0f);
830 /* manually notify session of new playlist here
831 because the playlists were constructed without notifying
833 PlaylistCreated (ret);
840 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
842 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::cut;
843 return cut_copy (pmf, ranges, result_is_hidden);
847 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
849 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::copy;
850 return cut_copy (pmf, ranges, result_is_hidden);
854 Playlist::cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
860 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
861 string new_name = _name;
865 if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
869 partition_internal (start, start+cnt-1, true, thawlist);
872 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
873 (*i)->thaw ("playlist cut");
876 maybe_save_state (_("cut"));
882 Playlist::copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
886 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
887 string new_name = _name;
891 cnt = min (_get_maximum_extent() - start, cnt);
892 return copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
896 Playlist::paste (Playlist& other, jack_nframes_t position, float times)
898 times = fabs (times);
899 jack_nframes_t old_length;
902 RegionLock rl1 (this);
903 RegionLock rl2 (&other);
905 old_length = _get_maximum_extent();
907 int itimes = (int) floor (times);
908 jack_nframes_t pos = position;
909 jack_nframes_t shift = other._get_maximum_extent();
910 layer_t top_layer = regions.size();
913 for (RegionList::iterator i = other.regions.begin(); i != other.regions.end(); ++i) {
914 Region *copy_of_region = createRegion (**i);
916 /* put these new regions on top of all existing ones, but preserve
917 the ordering they had in the original playlist.
920 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
921 add_region_internal (copy_of_region, copy_of_region->position() + pos);
926 possibly_splice_unlocked ();
928 /* XXX shall we handle fractional cases at some point? */
930 if (old_length != _get_maximum_extent()) {
931 notify_length_changed ();
937 maybe_save_state (_("paste"));
944 Playlist::duplicate (Region& region, jack_nframes_t position, float times)
946 times = fabs (times);
948 RegionLock rl (this);
949 int itimes = (int) floor (times);
950 jack_nframes_t pos = position;
953 Region *copy = createRegion (region);
954 add_region_internal (copy, pos, true);
955 pos += region.length();
958 if (floor (times) != times) {
959 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
961 _session.region_name (name, region.name(), false);
962 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
963 add_region_internal (sub, pos, true);
966 maybe_save_state (_("duplicate"));
970 Playlist::split_region (Region& region, jack_nframes_t playlist_position)
972 RegionLock rl (this);
974 if (!region.covers (playlist_position)) {
978 if (region.position() == playlist_position ||
979 region.last_frame() == playlist_position) {
985 jack_nframes_t before;
986 jack_nframes_t after;
990 before = playlist_position - region.position();
991 after = region.length() - before;
994 _session.region_name (before_name, region.name(), false);
995 left = createRegion (region, 0, before, before_name, region.layer(), Region::Flag (region.flags()|Region::LeftOfSplit));
997 _session.region_name (after_name, region.name(), false);
998 right = createRegion (region, before, after, after_name, region.layer(), Region::Flag (region.flags()|Region::RightOfSplit));
1000 add_region_internal (left, region.position(), true);
1001 add_region_internal (right, region.position() + before);
1003 uint64_t orig_layer_op = region.last_layer_op();
1004 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1005 if ((*i)->last_layer_op() > orig_layer_op) {
1006 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1010 left->set_last_layer_op ( orig_layer_op );
1011 right->set_last_layer_op ( orig_layer_op + 1);
1015 finalize_split_region (®ion, left, right);
1017 if (remove_region_internal (®ion, true)) {
1021 maybe_save_state (_("split"));
1025 Playlist::possibly_splice ()
1027 if (_edit_mode == Splice) {
1033 Playlist::possibly_splice_unlocked ()
1035 if (_edit_mode == Splice) {
1041 Playlist::splice_locked ()
1044 RegionLock rl (this);
1048 notify_length_changed ();
1052 Playlist::splice_unlocked ()
1055 notify_length_changed ();
1059 Playlist::core_splice ()
1063 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1065 RegionList::iterator next;
1070 if (next == regions.end()) {
1074 (*next)->set_position ((*i)->last_frame() + 1, this);
1081 Playlist::region_bounds_changed (Change what_changed, Region *region)
1083 if (in_set_state || _splicing || _nudging) {
1087 if (what_changed & ARDOUR::PositionChanged) {
1089 /* remove it from the list then add it back in
1090 the right place again.
1093 RegionSortByPosition cmp;
1095 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1097 if (i == regions.end()) {
1098 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1099 _name, region->name())
1105 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp),
1110 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1112 if (holding_state ()) {
1113 pending_bounds.push_back (region);
1115 if (_session.get_layer_model() == Session::MoveAddHigher) {
1116 /* it moved or changed length, so change the timestamp */
1117 timestamp_layer_op (*region);
1121 check_dependents (*region, false);
1122 notify_length_changed ();
1129 Playlist::region_changed_proxy (Change what_changed, Region* region)
1131 /* this makes a virtual call to the right kind of playlist ... */
1133 region_changed (what_changed, region);
1137 Playlist::region_changed (Change what_changed, Region* region)
1139 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1142 if (in_set_state || in_flush) {
1147 if (what_changed & BoundsChanged) {
1148 region_bounds_changed (what_changed, region);
1149 save = !(_splicing || _nudging);
1152 if ((what_changed & Region::MuteChanged) &&
1153 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1154 check_dependents (*region, false);
1157 if (what_changed & our_interests) {
1166 Playlist::clear (bool with_delete, bool with_save)
1168 RegionList::iterator i;
1172 RegionLock rl (this);
1177 for (i = tmp.begin(); i != tmp.end(); ++i) {
1178 notify_region_removed (*i);
1185 maybe_save_state (_("clear"));
1189 /***********************************************************************
1191 **********************************************************************/
1193 Playlist::RegionList *
1194 Playlist::regions_at (jack_nframes_t frame)
1197 RegionLock rlock (this);
1198 return find_regions_at (frame);
1202 Playlist::top_region_at (jack_nframes_t frame)
1205 RegionLock rlock (this);
1206 RegionList *rlist = find_regions_at (frame);
1209 if (rlist->size()) {
1210 RegionSortByLayer cmp;
1212 region = rlist->back();
1219 Playlist::RegionList *
1220 Playlist::find_regions_at (jack_nframes_t frame)
1222 RegionList *rlist = new RegionList;
1224 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1225 if ((*i)->covers (frame)) {
1226 rlist->push_back (*i);
1233 Playlist::RegionList *
1234 Playlist::regions_touched (jack_nframes_t start, jack_nframes_t end)
1236 RegionLock rlock (this);
1237 RegionList *rlist = new RegionList;
1239 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1240 if ((*i)->coverage (start, end) != OverlapNone) {
1241 rlist->push_back (*i);
1251 Playlist::find_next_region (jack_nframes_t frame, RegionPoint point, int dir)
1253 RegionLock rlock (this);
1255 jack_nframes_t closest = max_frames;
1257 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1259 jack_nframes_t distance;
1261 jack_nframes_t pos = 0;
1265 pos = r->first_frame ();
1268 pos = r->last_frame ();
1271 pos = r->adjust_to_sync (r->first_frame());
1276 case 1: /* forwards */
1279 if ((distance = pos - frame) < closest) {
1287 default: /* backwards */
1290 if ((distance = frame - pos) < closest) {
1302 /***********************************************************************/
1307 Playlist::mark_session_dirty ()
1309 if (!in_set_state && !holding_state ()) {
1310 _session.set_dirty();
1315 Playlist::set_state (const XMLNode& node)
1317 in_set_state = true;
1321 XMLNodeConstIterator niter;
1322 XMLPropertyList plist;
1323 XMLPropertyConstIterator piter;
1328 clear (false, false);
1330 if (node.name() != "Playlist") {
1331 in_set_state = false;
1335 plist = node.properties();
1337 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1341 if (prop->name() == X_("name")) {
1342 _name = prop->value();
1343 } else if (prop->name() == X_("orig_diskstream_id")) {
1344 _orig_diskstream_id = prop->value ();
1345 } else if (prop->name() == X_("frozen")) {
1346 _frozen = (prop->value() == X_("yes"));
1350 nlist = node.children();
1352 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1356 if (child->name() == "Region") {
1358 if ((region = createRegion (_session, *child, true)) == 0) {
1359 error << _("Playlist: cannot create region from state file") << endmsg;
1363 add_region (*region, region->position(), 1.0, false);
1365 // So that layer_op ordering doesn't get screwed up
1366 region->set_last_layer_op( region->layer());
1372 /* update dependents, which was not done during add_region_internal
1373 due to in_set_state being true
1376 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1377 check_dependents (**r, false);
1380 in_set_state = false;
1386 Playlist::get_state()
1392 Playlist::get_template()
1394 return state(false);
1398 Playlist::state (bool full_state)
1400 XMLNode *node = new XMLNode (X_("Playlist"));
1403 node->add_property (X_("name"), _name);
1405 _orig_diskstream_id.print (buf);
1406 node->add_property (X_("orig_diskstream_id"), buf);
1407 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1410 RegionLock rlock (this, false);
1412 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1413 node->add_child_nocopy ((*i)->get_state());
1418 node->add_child_copy (*_extra_xml);
1425 Playlist::empty() const
1427 return regions.empty();
1431 Playlist::get_maximum_extent () const
1433 RegionLock rlock (const_cast<Playlist *>(this));
1434 return _get_maximum_extent ();
1438 Playlist::_get_maximum_extent () const
1440 RegionList::const_iterator i;
1441 jack_nframes_t max_extent = 0;
1442 jack_nframes_t end = 0;
1444 for (i = regions.begin(); i != regions.end(); ++i) {
1445 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1454 Playlist::bump_name (string name, Session &session)
1456 string newname = name;
1459 newname = Playlist::bump_name_once (newname);
1460 } while (session.playlist_by_name(newname)!=NULL);
1466 Playlist::bump_name_once (string name)
1468 string::size_type period;
1471 if ((period = name.find_last_of ('.')) == string::npos) {
1478 sscanf (name.substr (period+1).c_str(), "%d", &version);
1479 snprintf (buf, sizeof(buf), "%d", version+1);
1481 newname = name.substr (0, period+1);
1489 Playlist::top_layer() const
1491 RegionLock rlock (const_cast<Playlist *> (this));
1494 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1495 top = max (top, (*i)->layer());
1501 Playlist::set_edit_mode (EditMode mode)
1506 /********************
1508 ********************/
1511 Playlist::relayer ()
1513 RegionList::iterator i;
1516 /* don't send multiple Modified notifications
1517 when multiple regions are relayered.
1522 if (_session.get_layer_model() == Session::MoveAddHigher ||
1523 _session.get_layer_model() == Session::AddHigher) {
1525 RegionSortByLastLayerOp cmp;
1526 RegionList copy = regions;
1530 for (i = copy.begin(); i != copy.end(); ++i) {
1531 (*i)->set_layer (layer++);
1536 /* Session::LaterHigher model */
1538 for (i = regions.begin(); i != regions.end(); ++i) {
1539 (*i)->set_layer (layer++);
1543 /* sending Modified means that various kinds of layering
1544 models operate correctly at the GUI
1545 level. slightly inefficient, but only slightly.
1547 We force a Modified signal here in case no layers actually
1556 /* XXX these layer functions are all deprecated */
1559 Playlist::raise_region (Region& region)
1561 uint32_t rsz = regions.size();
1562 layer_t target = region.layer() + 1U;
1564 if (target >= rsz) {
1565 /* its already at the effective top */
1569 move_region_to_layer (target, region, 1);
1573 Playlist::lower_region (Region& region)
1575 if (region.layer() == 0) {
1576 /* its already at the bottom */
1580 layer_t target = region.layer() - 1U;
1582 move_region_to_layer (target, region, -1);
1586 Playlist::raise_region_to_top (Region& region)
1588 /* does nothing useful if layering mode is later=higher */
1589 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1590 (_session.get_layer_model() == Session::AddHigher)) {
1591 timestamp_layer_op (region);
1597 Playlist::lower_region_to_bottom (Region& region)
1599 /* does nothing useful if layering mode is later=higher */
1600 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1601 (_session.get_layer_model() == Session::AddHigher)) {
1602 region.set_last_layer_op (0);
1608 Playlist::move_region_to_layer (layer_t target_layer, Region& region, int dir)
1610 RegionList::iterator i;
1611 typedef pair<Region*,layer_t> LayerInfo;
1612 list<LayerInfo> layerinfo;
1616 RegionLock rlock (const_cast<Playlist *> (this));
1618 for (i = regions.begin(); i != regions.end(); ++i) {
1620 if (®ion == *i) {
1626 /* region is moving up, move all regions on intermediate layers
1630 if ((*i)->layer() > region.layer() && (*i)->layer() <= target_layer) {
1631 dest = (*i)->layer() - 1;
1638 /* region is moving down, move all regions on intermediate layers
1642 if ((*i)->layer() < region.layer() && (*i)->layer() >= target_layer) {
1643 dest = (*i)->layer() + 1;
1653 newpair.second = dest;
1655 layerinfo.push_back (newpair);
1659 /* now reset the layers without holding the region lock */
1661 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1662 x->first->set_layer (x->second);
1665 region.set_layer (target_layer);
1667 /* now check all dependents */
1669 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1670 check_dependents (*(x->first), false);
1673 check_dependents (region, false);
1679 Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards)
1681 RegionList::iterator i;
1682 jack_nframes_t new_pos;
1688 RegionLock rlock (const_cast<Playlist *> (this));
1690 for (i = regions.begin(); i != regions.end(); ++i) {
1692 if ((*i)->position() >= start) {
1696 if ((*i)->last_frame() > max_frames - distance) {
1697 new_pos = max_frames - (*i)->length();
1699 new_pos = (*i)->position() + distance;
1704 if ((*i)->position() > distance) {
1705 new_pos = (*i)->position() - distance;
1711 (*i)->set_position (new_pos, this);
1719 maybe_save_state (_("nudged"));
1720 notify_length_changed ();
1726 Playlist::find_region (const ID& id) const
1728 RegionLock rlock (const_cast<Playlist*> (this));
1729 RegionList::const_iterator i;
1731 for (i = regions.begin(); i != regions.end(); ++i) {
1732 if ((*i)->id() == id) {
1741 Playlist::save_state (std::string why)
1743 if (!in_set_state) {
1744 StateManager::save_state (why);
1749 Playlist::dump () const
1753 cerr << "Playlist \"" << _name << "\" " << endl
1754 << regions.size() << " regions "
1757 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1759 cerr << " " << r->name() << " ["
1760 << r->start() << "+" << r->length()
1770 Playlist::set_frozen (bool yn)
1776 Playlist::timestamp_layer_op (Region& region)
1778 // struct timeval tv;
1779 // gettimeofday (&tv, 0);
1780 region.set_last_layer_op (++layer_op_counter);
1784 Playlist::maybe_save_state (string why)
1786 if (holding_state ()) {
1787 save_on_thaw = true;
1788 last_save_reason = why;