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::get_equivalent_regions (const Region& other, vector<Region*>& results)
604 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
605 if (Config->get_use_overlap_equivalency()) {
606 if ((*i)->overlap_equivalent (other)) {
607 results.push_back ((*i));
608 } else if ((*i)->equivalent (other)) {
609 results.push_back ((*i));
616 Playlist::get_region_list_equivalent_regions (const Region& other, vector<Region*>& results)
618 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
620 if ((*i) && (*i)->region_list_equivalent (other)) {
621 results.push_back (*i);
627 Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level)
631 partition_internal (start, end, false, thawlist);
633 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
634 (*i)->thaw ("separation");
637 maybe_save_state (_("separate"));
641 Playlist::partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist)
643 RegionLock rlock (this);
647 RegionList::iterator tmp;
649 jack_nframes_t pos1, pos2, pos3, pos4;
650 RegionList new_regions;
654 /* need to work from a copy, because otherwise the regions we add during the process
655 get operated on as well.
658 RegionList copy = regions;
660 for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
667 if (current->first_frame() == start && current->last_frame() == end) {
669 remove_region_internal (current);
674 if ((overlap = current->coverage (start, end)) == OverlapNone) {
678 pos1 = current->position();
681 pos4 = current->last_frame();
683 if (overlap == OverlapInternal) {
685 /* split: we need 3 new regions, the front, middle and end.
686 cut: we need 2 regions, the front and end.
691 ---------------*************************------------
694 ---------------*****++++++++++++++++====------------
696 ---------------*****----------------====------------
702 /* "middle" ++++++ */
704 _session.region_name (new_name, current->name(), false);
705 region = createRegion (*current, pos2 - pos1, pos3 - pos2, new_name,
706 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
707 add_region_internal (region, start, true);
708 new_regions.push_back (region);
713 _session.region_name (new_name, current->name(), false);
714 region = createRegion (*current, pos3 - pos1, pos4 - pos3, new_name,
715 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
717 add_region_internal (region, end, true);
718 new_regions.push_back (region);
723 thawlist.push_back (current);
724 current->trim_end (pos2, this);
726 } else if (overlap == OverlapEnd) {
730 ---------------*************************------------
733 ---------------**************+++++++++++------------
735 ---------------**************-----------------------
743 _session.region_name (new_name, current->name(), false);
744 region = createRegion (*current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
745 Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
746 add_region_internal (region, start, true);
747 new_regions.push_back (region);
753 thawlist.push_back (current);
754 current->trim_end (pos2, this);
756 } else if (overlap == OverlapStart) {
758 /* split: we need 2 regions: the front and the end.
759 cut: just trim current to skip the cut area
764 ---------------*************************------------
768 ---------------****+++++++++++++++++++++------------
770 -------------------*********************------------
777 _session.region_name (new_name, current->name(), false);
778 region = createRegion (*current, 0, pos3 - pos1, new_name,
779 regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
780 add_region_internal (region, pos1, true);
781 new_regions.push_back (region);
787 thawlist.push_back (current);
788 current->trim_front (pos3, this);
790 } else if (overlap == OverlapExternal) {
792 /* split: no split required.
793 cut: remove the region.
798 ---------------*************************------------
802 ---------------*************************------------
804 ----------------------------------------------------
809 remove_region_internal (current);
811 new_regions.push_back (current);
815 in_partition = false;
817 for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
818 check_dependents (**i, false);
823 Playlist::cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
827 jack_nframes_t start;
829 if (ranges.empty()) {
833 start = ranges.front().start;
836 for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
838 pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
840 if (i == ranges.begin()) {
844 /* paste the next section into the nascent playlist,
845 offset to reflect the start of the first range we
849 ret->paste (*pl, (*i).start - start, 1.0f);
855 /* manually notify session of new playlist here
856 because the playlists were constructed without notifying
858 PlaylistCreated (ret);
865 Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
867 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::cut;
868 return cut_copy (pmf, ranges, result_is_hidden);
872 Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
874 Playlist* (Playlist::*pmf)(jack_nframes_t,jack_nframes_t,bool) = &Playlist::copy;
875 return cut_copy (pmf, ranges, result_is_hidden);
879 Playlist::cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
885 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
886 string new_name = _name;
890 if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
894 partition_internal (start, start+cnt-1, true, thawlist);
897 for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
898 (*i)->thaw ("playlist cut");
901 maybe_save_state (_("cut"));
907 Playlist::copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden)
911 snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
912 string new_name = _name;
916 cnt = min (_get_maximum_extent() - start, cnt);
917 return copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
921 Playlist::paste (Playlist& other, jack_nframes_t position, float times)
923 times = fabs (times);
924 jack_nframes_t old_length;
927 RegionLock rl1 (this);
928 RegionLock rl2 (&other);
930 old_length = _get_maximum_extent();
932 int itimes = (int) floor (times);
933 jack_nframes_t pos = position;
934 jack_nframes_t shift = other._get_maximum_extent();
935 layer_t top_layer = regions.size();
938 for (RegionList::iterator i = other.regions.begin(); i != other.regions.end(); ++i) {
939 Region *copy_of_region = createRegion (**i);
941 /* put these new regions on top of all existing ones, but preserve
942 the ordering they had in the original playlist.
945 copy_of_region->set_layer (copy_of_region->layer() + top_layer);
946 add_region_internal (copy_of_region, copy_of_region->position() + pos);
951 possibly_splice_unlocked ();
953 /* XXX shall we handle fractional cases at some point? */
955 if (old_length != _get_maximum_extent()) {
956 notify_length_changed ();
962 maybe_save_state (_("paste"));
969 Playlist::duplicate (Region& region, jack_nframes_t position, float times)
971 times = fabs (times);
973 RegionLock rl (this);
974 int itimes = (int) floor (times);
975 jack_nframes_t pos = position;
978 Region *copy = createRegion (region);
979 add_region_internal (copy, pos, true);
980 pos += region.length();
983 if (floor (times) != times) {
984 jack_nframes_t length = (jack_nframes_t) floor (region.length() * (times - floor (times)));
986 _session.region_name (name, region.name(), false);
987 Region *sub = createRegion (region, 0, length, name, region.layer(), region.flags());
988 add_region_internal (sub, pos, true);
991 maybe_save_state (_("duplicate"));
995 Playlist::split_region (Region& region, jack_nframes_t playlist_position)
997 RegionLock rl (this);
999 if (!region.covers (playlist_position)) {
1003 if (region.position() == playlist_position ||
1004 region.last_frame() == playlist_position) {
1010 jack_nframes_t before;
1011 jack_nframes_t after;
1015 before = playlist_position - region.position();
1016 after = region.length() - before;
1019 _session.region_name (before_name, region.name(), false);
1020 left = createRegion (region, 0, before, before_name, region.layer(), Region::Flag (region.flags()|Region::LeftOfSplit));
1022 _session.region_name (after_name, region.name(), false);
1023 right = createRegion (region, before, after, after_name, region.layer(), Region::Flag (region.flags()|Region::RightOfSplit));
1025 add_region_internal (left, region.position(), true);
1026 add_region_internal (right, region.position() + before);
1028 uint64_t orig_layer_op = region.last_layer_op();
1029 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1030 if ((*i)->last_layer_op() > orig_layer_op) {
1031 (*i)->set_last_layer_op( (*i)->last_layer_op() + 1 );
1035 left->set_last_layer_op ( orig_layer_op );
1036 right->set_last_layer_op ( orig_layer_op + 1);
1040 finalize_split_region (®ion, left, right);
1042 if (remove_region_internal (®ion, true)) {
1046 maybe_save_state (_("split"));
1050 Playlist::possibly_splice ()
1052 if (_edit_mode == Splice) {
1058 Playlist::possibly_splice_unlocked ()
1060 if (_edit_mode == Splice) {
1066 Playlist::splice_locked ()
1069 RegionLock rl (this);
1073 notify_length_changed ();
1077 Playlist::splice_unlocked ()
1080 notify_length_changed ();
1084 Playlist::core_splice ()
1088 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1090 RegionList::iterator next;
1095 if (next == regions.end()) {
1099 (*next)->set_position ((*i)->last_frame() + 1, this);
1106 Playlist::region_bounds_changed (Change what_changed, Region *region)
1108 if (in_set_state || _splicing || _nudging) {
1112 if (what_changed & ARDOUR::PositionChanged) {
1114 /* remove it from the list then add it back in
1115 the right place again.
1118 RegionSortByPosition cmp;
1120 RegionList::iterator i = find (regions.begin(), regions.end(), region);
1122 if (i == regions.end()) {
1123 warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"),
1124 _name, region->name())
1130 regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp),
1135 if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
1137 if (holding_state ()) {
1138 pending_bounds.push_back (region);
1140 if (_session.get_layer_model() == Session::MoveAddHigher) {
1141 /* it moved or changed length, so change the timestamp */
1142 timestamp_layer_op (*region);
1146 check_dependents (*region, false);
1147 notify_length_changed ();
1154 Playlist::region_changed_proxy (Change what_changed, Region* region)
1156 /* this makes a virtual call to the right kind of playlist ... */
1158 region_changed (what_changed, region);
1162 Playlist::region_changed (Change what_changed, Region* region)
1164 Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged);
1167 if (in_set_state || in_flush) {
1172 if (what_changed & BoundsChanged) {
1173 region_bounds_changed (what_changed, region);
1174 save = !(_splicing || _nudging);
1177 if ((what_changed & Region::MuteChanged) &&
1178 !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
1179 check_dependents (*region, false);
1182 if (what_changed & our_interests) {
1191 Playlist::clear (bool with_delete, bool with_save)
1193 RegionList::iterator i;
1197 RegionLock rl (this);
1202 for (i = tmp.begin(); i != tmp.end(); ++i) {
1203 notify_region_removed (*i);
1210 maybe_save_state (_("clear"));
1214 /***********************************************************************
1216 **********************************************************************/
1218 Playlist::RegionList *
1219 Playlist::regions_at (jack_nframes_t frame)
1222 RegionLock rlock (this);
1223 return find_regions_at (frame);
1227 Playlist::top_region_at (jack_nframes_t frame)
1230 RegionLock rlock (this);
1231 RegionList *rlist = find_regions_at (frame);
1234 if (rlist->size()) {
1235 RegionSortByLayer cmp;
1237 region = rlist->back();
1244 Playlist::RegionList *
1245 Playlist::find_regions_at (jack_nframes_t frame)
1247 RegionList *rlist = new RegionList;
1249 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1250 if ((*i)->covers (frame)) {
1251 rlist->push_back (*i);
1258 Playlist::RegionList *
1259 Playlist::regions_touched (jack_nframes_t start, jack_nframes_t end)
1261 RegionLock rlock (this);
1262 RegionList *rlist = new RegionList;
1264 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1265 if ((*i)->coverage (start, end) != OverlapNone) {
1266 rlist->push_back (*i);
1276 Playlist::find_next_region (jack_nframes_t frame, RegionPoint point, int dir)
1278 RegionLock rlock (this);
1280 jack_nframes_t closest = max_frames;
1282 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1284 jack_nframes_t distance;
1286 jack_nframes_t pos = 0;
1290 pos = r->first_frame ();
1293 pos = r->last_frame ();
1296 pos = r->adjust_to_sync (r->first_frame());
1301 case 1: /* forwards */
1304 if ((distance = pos - frame) < closest) {
1312 default: /* backwards */
1315 if ((distance = frame - pos) < closest) {
1327 /***********************************************************************/
1332 Playlist::mark_session_dirty ()
1334 if (!in_set_state && !holding_state ()) {
1335 _session.set_dirty();
1340 Playlist::set_state (const XMLNode& node)
1342 in_set_state = true;
1346 XMLNodeConstIterator niter;
1347 XMLPropertyList plist;
1348 XMLPropertyConstIterator piter;
1353 clear (false, false);
1355 if (node.name() != "Playlist") {
1356 in_set_state = false;
1360 plist = node.properties();
1362 for (piter = plist.begin(); piter != plist.end(); ++piter) {
1366 if (prop->name() == X_("name")) {
1367 _name = prop->value();
1368 } else if (prop->name() == X_("orig_diskstream_id")) {
1369 _orig_diskstream_id = prop->value ();
1370 } else if (prop->name() == X_("frozen")) {
1371 _frozen = (prop->value() == X_("yes"));
1375 nlist = node.children();
1377 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1381 if (child->name() == "Region") {
1383 if ((region = createRegion (_session, *child, true)) == 0) {
1384 error << _("Playlist: cannot create region from state file") << endmsg;
1388 add_region (*region, region->position(), 1.0, false);
1390 // So that layer_op ordering doesn't get screwed up
1391 region->set_last_layer_op( region->layer());
1397 /* update dependents, which was not done during add_region_internal
1398 due to in_set_state being true
1401 for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
1402 check_dependents (**r, false);
1405 in_set_state = false;
1411 Playlist::get_state()
1417 Playlist::get_template()
1419 return state(false);
1423 Playlist::state (bool full_state)
1425 XMLNode *node = new XMLNode (X_("Playlist"));
1428 node->add_property (X_("name"), _name);
1430 _orig_diskstream_id.print (buf);
1431 node->add_property (X_("orig_diskstream_id"), buf);
1432 node->add_property (X_("frozen"), _frozen ? "yes" : "no");
1435 RegionLock rlock (this, false);
1437 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
1438 node->add_child_nocopy ((*i)->get_state());
1443 node->add_child_copy (*_extra_xml);
1450 Playlist::empty() const
1452 return regions.empty();
1456 Playlist::get_maximum_extent () const
1458 RegionLock rlock (const_cast<Playlist *>(this));
1459 return _get_maximum_extent ();
1463 Playlist::_get_maximum_extent () const
1465 RegionList::const_iterator i;
1466 jack_nframes_t max_extent = 0;
1467 jack_nframes_t end = 0;
1469 for (i = regions.begin(); i != regions.end(); ++i) {
1470 if ((end = (*i)->position() + (*i)->length()) > max_extent) {
1479 Playlist::bump_name (string name, Session &session)
1481 string newname = name;
1484 newname = Playlist::bump_name_once (newname);
1485 } while (session.playlist_by_name(newname)!=NULL);
1491 Playlist::bump_name_once (string name)
1493 string::size_type period;
1496 if ((period = name.find_last_of ('.')) == string::npos) {
1503 sscanf (name.substr (period+1).c_str(), "%d", &version);
1504 snprintf (buf, sizeof(buf), "%d", version+1);
1506 newname = name.substr (0, period+1);
1514 Playlist::top_layer() const
1516 RegionLock rlock (const_cast<Playlist *> (this));
1519 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1520 top = max (top, (*i)->layer());
1526 Playlist::set_edit_mode (EditMode mode)
1531 /********************
1533 ********************/
1536 Playlist::relayer ()
1538 RegionList::iterator i;
1541 /* don't send multiple Modified notifications
1542 when multiple regions are relayered.
1547 if (_session.get_layer_model() == Session::MoveAddHigher ||
1548 _session.get_layer_model() == Session::AddHigher) {
1550 RegionSortByLastLayerOp cmp;
1551 RegionList copy = regions;
1555 for (i = copy.begin(); i != copy.end(); ++i) {
1556 (*i)->set_layer (layer++);
1561 /* Session::LaterHigher model */
1563 for (i = regions.begin(); i != regions.end(); ++i) {
1564 (*i)->set_layer (layer++);
1568 /* sending Modified means that various kinds of layering
1569 models operate correctly at the GUI
1570 level. slightly inefficient, but only slightly.
1572 We force a Modified signal here in case no layers actually
1581 /* XXX these layer functions are all deprecated */
1584 Playlist::raise_region (Region& region)
1586 uint32_t rsz = regions.size();
1587 layer_t target = region.layer() + 1U;
1589 if (target >= rsz) {
1590 /* its already at the effective top */
1594 move_region_to_layer (target, region, 1);
1598 Playlist::lower_region (Region& region)
1600 if (region.layer() == 0) {
1601 /* its already at the bottom */
1605 layer_t target = region.layer() - 1U;
1607 move_region_to_layer (target, region, -1);
1611 Playlist::raise_region_to_top (Region& region)
1613 /* does nothing useful if layering mode is later=higher */
1614 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1615 (_session.get_layer_model() == Session::AddHigher)) {
1616 timestamp_layer_op (region);
1622 Playlist::lower_region_to_bottom (Region& region)
1624 /* does nothing useful if layering mode is later=higher */
1625 if ((_session.get_layer_model() == Session::MoveAddHigher) ||
1626 (_session.get_layer_model() == Session::AddHigher)) {
1627 region.set_last_layer_op (0);
1633 Playlist::move_region_to_layer (layer_t target_layer, Region& region, int dir)
1635 RegionList::iterator i;
1636 typedef pair<Region*,layer_t> LayerInfo;
1637 list<LayerInfo> layerinfo;
1641 RegionLock rlock (const_cast<Playlist *> (this));
1643 for (i = regions.begin(); i != regions.end(); ++i) {
1645 if (®ion == *i) {
1651 /* region is moving up, move all regions on intermediate layers
1655 if ((*i)->layer() > region.layer() && (*i)->layer() <= target_layer) {
1656 dest = (*i)->layer() - 1;
1663 /* region is moving down, move all regions on intermediate layers
1667 if ((*i)->layer() < region.layer() && (*i)->layer() >= target_layer) {
1668 dest = (*i)->layer() + 1;
1678 newpair.second = dest;
1680 layerinfo.push_back (newpair);
1684 /* now reset the layers without holding the region lock */
1686 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1687 x->first->set_layer (x->second);
1690 region.set_layer (target_layer);
1692 /* now check all dependents */
1694 for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
1695 check_dependents (*(x->first), false);
1698 check_dependents (region, false);
1704 Playlist::nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards)
1706 RegionList::iterator i;
1707 jack_nframes_t new_pos;
1713 RegionLock rlock (const_cast<Playlist *> (this));
1715 for (i = regions.begin(); i != regions.end(); ++i) {
1717 if ((*i)->position() >= start) {
1721 if ((*i)->last_frame() > max_frames - distance) {
1722 new_pos = max_frames - (*i)->length();
1724 new_pos = (*i)->position() + distance;
1729 if ((*i)->position() > distance) {
1730 new_pos = (*i)->position() - distance;
1736 (*i)->set_position (new_pos, this);
1744 maybe_save_state (_("nudged"));
1745 notify_length_changed ();
1751 Playlist::find_region (const ID& id) const
1753 RegionLock rlock (const_cast<Playlist*> (this));
1754 RegionList::const_iterator i;
1756 for (i = regions.begin(); i != regions.end(); ++i) {
1757 if ((*i)->id() == id) {
1766 Playlist::save_state (std::string why)
1768 if (!in_set_state) {
1769 StateManager::save_state (why);
1774 Playlist::dump () const
1778 cerr << "Playlist \"" << _name << "\" " << endl
1779 << regions.size() << " regions "
1782 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
1784 cerr << " " << r->name() << " ["
1785 << r->start() << "+" << r->length()
1795 Playlist::set_frozen (bool yn)
1801 Playlist::timestamp_layer_op (Region& region)
1803 // struct timeval tv;
1804 // gettimeofday (&tv, 0);
1805 region.set_last_layer_op (++layer_op_counter);
1809 Playlist::maybe_save_state (string why)
1811 if (holding_state ()) {
1812 save_on_thaw = true;
1813 last_save_reason = why;