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.
26 #include <sigc++/bind.h>
27 #include <sigc++/class_slot.h>
29 #include <glibmm/thread.h>
30 #include "pbd/xml++.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/enumwriter.h"
34 #include "ardour/region.h"
35 #include "ardour/playlist.h"
36 #include "ardour/session.h"
37 #include "ardour/source.h"
38 #include "ardour/tempo.h"
39 #include "ardour/region_factory.h"
40 #include "ardour/filter.h"
41 #include "ardour/profile.h"
42 #include "ardour/utils.h"
47 using namespace ARDOUR;
50 Change Region::FadeChanged = ARDOUR::new_change ();
51 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
52 Change Region::MuteChanged = ARDOUR::new_change ();
53 Change Region::OpacityChanged = ARDOUR::new_change ();
54 Change Region::LockChanged = ARDOUR::new_change ();
55 Change Region::LayerChanged = ARDOUR::new_change ();
56 Change Region::HiddenChanged = ARDOUR::new_change ();
58 sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
60 /* derived-from-derived constructor (no sources in constructor) */
61 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
62 : SessionObject(s, name)
69 , _positional_lock_style(AudioTime)
70 , _sync_position(_start)
72 , _first_edit(EditChangesNothing)
77 , _pending_changed(Change (0))
80 /* no sources at this point */
83 /** Basic Region constructor (single source) */
84 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
85 : SessionObject(src->session(), name)
92 , _positional_lock_style(AudioTime)
93 , _sync_position(_start)
95 , _first_edit(EditChangesNothing)
97 , _ancestral_start (0)
98 , _ancestral_length (0)
101 , _valid_transients(false)
102 , _read_data_count(0)
103 , _pending_changed(Change (0))
107 _sources.push_back (src);
108 _master_sources.push_back (src);
110 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
112 assert(_sources.size() > 0);
113 _positional_lock_style = AudioTime;
116 /** Basic Region constructor (many sources) */
117 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
118 : SessionObject(srcs.front()->session(), name)
125 , _positional_lock_style(AudioTime)
126 , _sync_position(_start)
128 , _first_edit(EditChangesNothing)
132 , _read_data_count(0)
133 , _pending_changed(Change (0))
137 assert(_sources.size() > 0);
140 /** Create a new Region from part of an existing one */
141 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
142 : SessionObject(other->session(), name)
143 , _type (other->data_type())
146 _start = other->_start + offset;
147 copy_stuff (other, offset, length, name, layer, flags);
149 /* if the other region had a distinct sync point
150 set, then continue to use it as best we can.
151 otherwise, reset sync point back to start.
154 if (other->flags() & SyncMarked) {
155 if (other->_sync_position < _start) {
156 _flags = Flag (_flags & ~SyncMarked);
157 _sync_position = _start;
159 _sync_position = other->_sync_position;
162 _flags = Flag (_flags & ~SyncMarked);
163 _sync_position = _start;
166 if (Profile->get_sae()) {
167 /* reset sync point to start if its ended up
168 outside region bounds.
171 if (_sync_position < _start || _sync_position >= _start + _length) {
172 _flags = Flag (_flags & ~SyncMarked);
173 _sync_position = _start;
178 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
179 : SessionObject(other->session(), name)
180 , _type (other->data_type())
182 /* create a new Region exactly like another but starting at 0 in its sources */
185 copy_stuff (other, 0, length, name, layer, flags);
187 /* sync pos is relative to start of file. our start-in-file is now zero,
188 so set our sync position to whatever the the difference between
189 _start and _sync_pos was in the other region.
191 result is that our new sync pos points to the same point in our source(s)
192 as the sync in the other region did in its source(s).
194 since we start at zero in our source(s), it is not possible to use a sync point that
195 is before the start. reset it to _start if that was true in the other region.
198 if (other->flags() & SyncMarked) {
199 if (other->_start < other->_sync_position) {
200 /* sync pos was after the start point of the other region */
201 _sync_position = other->_sync_position - other->_start;
203 /* sync pos was before the start point of the other region. not possible here. */
204 _flags = Flag (_flags & ~SyncMarked);
205 _sync_position = _start;
208 _flags = Flag (_flags & ~SyncMarked);
209 _sync_position = _start;
212 if (Profile->get_sae()) {
213 /* reset sync point to start if its ended up
214 outside region bounds.
217 if (_sync_position < _start || _sync_position >= _start + _length) {
218 _flags = Flag (_flags & ~SyncMarked);
219 _sync_position = _start;
223 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
225 _positional_lock_style = other->_positional_lock_style;
226 _first_edit = other->_first_edit;
229 /** Pure copy constructor */
230 Region::Region (boost::shared_ptr<const Region> other)
231 : SessionObject(other->session(), other->name())
232 , _type(other->data_type())
233 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
234 , _start(other->_start)
235 , _length(other->_length)
236 , _position(other->_position)
237 , _last_position(other->_last_position)
238 , _positional_lock_style(other->_positional_lock_style)
239 , _sync_position(other->_sync_position)
240 , _layer(other->_layer)
241 , _first_edit(EditChangesID)
243 , _ancestral_start (other->_ancestral_start)
244 , _ancestral_length (other->_ancestral_length)
245 , _stretch (other->_stretch)
246 , _shift (other->_shift)
247 , _valid_transients(false)
248 , _read_data_count(0)
249 , _pending_changed(Change(0))
250 , _last_layer_op(other->_last_layer_op)
252 other->_first_edit = EditChangesName;
254 if (other->_extra_xml) {
255 _extra_xml = new XMLNode (*other->_extra_xml);
260 use_sources (other->_sources);
261 assert(_sources.size() > 0);
264 Region::Region (const SourceList& srcs, const XMLNode& node)
265 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
266 , _type(DataType::NIL) // to be loaded from XML
272 , _positional_lock_style(AudioTime)
273 , _sync_position(_start)
275 , _first_edit(EditChangesNothing)
279 , _read_data_count(0)
280 , _pending_changed(Change(0))
283 set<boost::shared_ptr<Source> > unique_srcs;
285 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
286 _sources.push_back (*i);
287 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
288 unique_srcs.insert (*i);
291 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
292 _master_sources.push_back (*i);
293 if (unique_srcs.find (*i) == unique_srcs.end()) {
294 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
298 if (set_state (node)) {
299 throw failed_constructor();
302 assert(_type != DataType::NIL);
303 assert(_sources.size() > 0);
306 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
307 : SessionObject(src->session(), X_("error: XML did not reset this"))
308 , _type(DataType::NIL)
314 , _positional_lock_style(AudioTime)
315 , _sync_position(_start)
317 , _first_edit(EditChangesNothing)
321 , _read_data_count(0)
322 , _pending_changed(Change(0))
325 _sources.push_back (src);
327 if (set_state (node)) {
328 throw failed_constructor();
331 assert(_type != DataType::NIL);
332 assert(_sources.size() > 0);
337 boost::shared_ptr<Playlist> pl (playlist());
340 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
341 (*i)->remove_playlist (pl);
343 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
344 (*i)->remove_playlist (pl);
349 GoingAway (); /* EMIT SIGNAL */
353 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
356 _pending_changed = Change (0);
357 _read_data_count = 0;
358 _valid_transients = false;
361 _last_length = length;
362 _sync_position = other->_sync_position;
363 _ancestral_start = other->_ancestral_start;
364 _ancestral_length = other->_ancestral_length;
365 _stretch = other->_stretch;
366 _shift = other->_shift;
371 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
372 _first_edit = EditChangesNothing;
374 _positional_lock_style = AudioTime;
376 use_sources (other->_sources);
380 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
382 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
384 boost::shared_ptr<Playlist> pl (wpl.lock());
386 if (old_playlist == pl) {
394 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
395 (*i)->remove_playlist (_playlist);
396 (*i)->add_playlist (pl);
398 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
399 (*i)->remove_playlist (_playlist);
400 (*i)->add_playlist (pl);
403 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
404 (*i)->add_playlist (pl);
406 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
407 (*i)->add_playlist (pl);
412 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
413 (*i)->remove_playlist (old_playlist);
415 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
416 (*i)->remove_playlist (old_playlist);
423 Region::set_name (const std::string& str)
426 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
427 assert(_name == str);
428 send_change (ARDOUR::NameChanged);
435 Region::set_length (nframes_t len, void *src)
437 //cerr << "Region::set_length() len = " << len << endl;
438 if (_flags & Locked) {
442 if (_length != len && len != 0) {
444 /* check that the current _position wouldn't make the new
448 if (max_frames - len < _position) {
452 if (!verify_length (len)) {
457 _last_length = _length;
460 _flags = Region::Flag (_flags & ~WholeFile);
464 invalidate_transients ();
470 send_change (LengthChanged);
475 Region::maybe_uncopy ()
480 Region::first_edit ()
482 boost::shared_ptr<Playlist> pl (playlist());
484 if (_first_edit != EditChangesNothing && pl) {
486 _name = pl->session().new_region_name (_name);
487 _first_edit = EditChangesNothing;
489 send_change (ARDOUR::NameChanged);
490 RegionFactory::CheckNewRegion (shared_from_this());
495 Region::at_natural_position () const
497 boost::shared_ptr<Playlist> pl (playlist());
503 boost::shared_ptr<Region> whole_file_region = get_parent();
505 if (whole_file_region) {
506 if (_position == whole_file_region->position() + _start) {
515 Region::move_to_natural_position (void *src)
517 boost::shared_ptr<Playlist> pl (playlist());
523 boost::shared_ptr<Region> whole_file_region = get_parent();
525 if (whole_file_region) {
526 set_position (whole_file_region->position() + _start, src);
531 Region::special_set_position (nframes_t pos)
533 /* this is used when creating a whole file region as
534 a way to store its "natural" or "captured" position.
537 _position = _position;
542 Region::set_position_lock_style (PositionLockStyle ps)
544 boost::shared_ptr<Playlist> pl (playlist());
550 _positional_lock_style = ps;
552 if (_positional_lock_style == MusicTime) {
553 pl->session().tempo_map().bbt_time (_position, _bbt_time);
559 Region::update_position_after_tempo_map_change ()
561 boost::shared_ptr<Playlist> pl (playlist());
563 if (!pl || _positional_lock_style != MusicTime) {
567 TempoMap& map (pl->session().tempo_map());
568 nframes_t pos = map.frame_time (_bbt_time);
569 set_position_internal (pos, false);
573 Region::set_position (nframes_t pos, void *src)
579 set_position_internal (pos, true);
583 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
585 if (_position != pos) {
586 _last_position = _position;
589 /* check that the new _position wouldn't make the current
590 length impossible - if so, change the length.
592 XXX is this the right thing to do?
595 if (max_frames - _length < _position) {
596 _last_length = _length;
597 _length = max_frames - _position;
600 if (allow_bbt_recompute) {
601 recompute_position_from_lock_style ();
604 invalidate_transients ();
607 /* do this even if the position is the same. this helps out
608 a GUI that has moved its representation already.
611 send_change (PositionChanged);
615 Region::set_position_on_top (nframes_t pos, void *src)
617 if (_flags & Locked) {
621 if (_position != pos) {
622 _last_position = _position;
626 boost::shared_ptr<Playlist> pl (playlist());
629 pl->raise_region_to_top (shared_from_this ());
632 /* do this even if the position is the same. this helps out
633 a GUI that has moved its representation already.
636 send_change (PositionChanged);
640 Region::recompute_position_from_lock_style ()
642 if (_positional_lock_style == MusicTime) {
643 boost::shared_ptr<Playlist> pl (playlist());
645 pl->session().tempo_map().bbt_time (_position, _bbt_time);
651 Region::nudge_position (nframes64_t n, void *src)
653 if (_flags & Locked) {
661 _last_position = _position;
664 if (_position > max_frames - n) {
665 _position = max_frames;
670 if (_position < (nframes_t) -n) {
677 send_change (PositionChanged);
681 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
683 _ancestral_length = l;
684 _ancestral_start = s;
690 Region::set_start (nframes_t pos, void *src)
692 if (_flags & (Locked|PositionLocked)) {
695 /* This just sets the start, nothing else. It effectively shifts
696 the contents of the Region within the overall extent of the Source,
697 without changing the Region's position or length
702 if (!verify_start (pos)) {
707 _flags = Region::Flag (_flags & ~WholeFile);
709 invalidate_transients ();
711 send_change (StartChanged);
716 Region::trim_start (nframes_t new_position, void *src)
718 if (_flags & (Locked|PositionLocked)) {
724 if (new_position > _position) {
725 start_shift = new_position - _position;
727 start_shift = -(_position - new_position);
730 if (start_shift > 0) {
732 if (_start > max_frames - start_shift) {
733 new_start = max_frames;
735 new_start = _start + start_shift;
738 if (!verify_start (new_start)) {
742 } else if (start_shift < 0) {
744 if (_start < (nframes_t) -start_shift) {
747 new_start = _start + start_shift;
753 if (new_start == _start) {
758 _flags = Region::Flag (_flags & ~WholeFile);
761 send_change (StartChanged);
765 Region::trim_front (nframes_t new_position, void *src)
767 if (_flags & Locked) {
771 nframes_t end = last_frame();
772 nframes_t source_zero;
774 if (_position > _start) {
775 source_zero = _position - _start;
777 source_zero = 0; // its actually negative, but this will work for us
780 if (new_position < end) { /* can't trim it zero or negative length */
784 /* can't trim it back passed where source position zero is located */
786 new_position = max (new_position, source_zero);
789 if (new_position > _position) {
790 newlen = _length - (new_position - _position);
792 newlen = _length + (_position - new_position);
795 trim_to_internal (new_position, newlen, src);
797 recompute_at_start ();
803 Region::trim_end (nframes_t new_endpoint, void *src)
805 if (_flags & Locked) {
809 if (new_endpoint > _position) {
810 trim_to_internal (_position, new_endpoint - _position, this);
818 Region::trim_to (nframes_t position, nframes_t length, void *src)
820 if (_flags & Locked) {
824 trim_to_internal (position, length, src);
827 recompute_at_start ();
833 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
838 if (_flags & Locked) {
842 if (position > _position) {
843 start_shift = position - _position;
845 start_shift = -(_position - position);
848 if (start_shift > 0) {
850 if (_start > max_frames - start_shift) {
851 new_start = max_frames;
853 new_start = _start + start_shift;
857 } else if (start_shift < 0) {
859 if (_start < (nframes_t) -start_shift) {
862 new_start = _start + start_shift;
868 if (!verify_start_and_length (new_start, length)) {
872 Change what_changed = Change (0);
874 if (_start != new_start) {
876 what_changed = Change (what_changed|StartChanged);
878 if (_length != length) {
880 _last_length = _length;
883 what_changed = Change (what_changed|LengthChanged);
885 if (_position != position) {
887 _last_position = _position;
889 _position = position;
890 what_changed = Change (what_changed|PositionChanged);
893 _flags = Region::Flag (_flags & ~WholeFile);
895 if (what_changed & (StartChanged|LengthChanged)) {
900 send_change (what_changed);
905 Region::set_hidden (bool yn)
907 if (hidden() != yn) {
910 _flags = Flag (_flags|Hidden);
912 _flags = Flag (_flags & ~Hidden);
915 send_change (HiddenChanged);
920 Region::set_muted (bool yn)
925 _flags = Flag (_flags|Muted);
927 _flags = Flag (_flags & ~Muted);
930 send_change (MuteChanged);
935 Region::set_opaque (bool yn)
937 if (opaque() != yn) {
939 _flags = Flag (_flags|Opaque);
941 _flags = Flag (_flags & ~Opaque);
943 send_change (OpacityChanged);
948 Region::set_locked (bool yn)
950 if (locked() != yn) {
952 _flags = Flag (_flags|Locked);
954 _flags = Flag (_flags & ~Locked);
956 send_change (LockChanged);
961 Region::set_position_locked (bool yn)
963 if (position_locked() != yn) {
965 _flags = Flag (_flags|PositionLocked);
967 _flags = Flag (_flags & ~PositionLocked);
969 send_change (LockChanged);
974 Region::set_sync_position (nframes_t absolute_pos)
978 file_pos = _start + (absolute_pos - _position);
980 if (file_pos != _sync_position) {
982 _sync_position = file_pos;
983 _flags = Flag (_flags|SyncMarked);
988 send_change (SyncOffsetChanged);
993 Region::clear_sync_position ()
995 if (_flags & SyncMarked) {
996 _flags = Flag (_flags & ~SyncMarked);
1001 send_change (SyncOffsetChanged);
1006 Region::sync_offset (int& dir) const
1008 /* returns the sync point relative the first frame of the region */
1010 if (_flags & SyncMarked) {
1011 if (_sync_position > _start) {
1013 return _sync_position - _start;
1016 return _start - _sync_position;
1025 Region::adjust_to_sync (nframes_t pos) const
1028 nframes_t offset = sync_offset (sync_dir);
1030 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1039 if (max_frames - pos > offset) {
1048 Region::sync_position() const
1050 if (_flags & SyncMarked) {
1051 return _sync_position;
1060 boost::shared_ptr<Playlist> pl (playlist());
1062 pl->raise_region (shared_from_this ());
1069 boost::shared_ptr<Playlist> pl (playlist());
1071 pl->lower_region (shared_from_this ());
1077 Region::raise_to_top ()
1079 boost::shared_ptr<Playlist> pl (playlist());
1081 pl->raise_region_to_top (shared_from_this());
1086 Region::lower_to_bottom ()
1088 boost::shared_ptr<Playlist> pl (playlist());
1090 pl->lower_region_to_bottom (shared_from_this());
1095 Region::set_layer (layer_t l)
1100 send_change (LayerChanged);
1105 Region::state (bool full_state)
1107 XMLNode *node = new XMLNode ("Region");
1109 const char* fe = NULL;
1111 _id.print (buf, sizeof (buf));
1112 node->add_property ("id", buf);
1113 node->add_property ("name", _name);
1114 node->add_property ("type", _type.to_string());
1115 snprintf (buf, sizeof (buf), "%u", _start);
1116 node->add_property ("start", buf);
1117 snprintf (buf, sizeof (buf), "%u", _length);
1118 node->add_property ("length", buf);
1119 snprintf (buf, sizeof (buf), "%u", _position);
1120 node->add_property ("position", buf);
1121 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1122 node->add_property ("ancestral-start", buf);
1123 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1124 node->add_property ("ancestral-length", buf);
1125 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1126 node->add_property ("stretch", buf);
1127 snprintf (buf, sizeof (buf), "%.12g", _shift);
1128 node->add_property ("shift", buf);
1130 switch (_first_edit) {
1131 case EditChangesNothing:
1134 case EditChangesName:
1140 default: /* should be unreachable but makes g++ happy */
1145 node->add_property ("first-edit", fe);
1147 /* note: flags are stored by derived classes */
1149 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1150 node->add_property ("layer", buf);
1151 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1152 node->add_property ("sync-position", buf);
1154 if (_positional_lock_style != AudioTime) {
1155 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1158 node->add_property ("bbt-position", str.str());
1165 Region::get_state ()
1167 return state (true);
1171 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1173 const XMLNodeList& nlist = node.children();
1174 const XMLProperty *prop;
1177 /* this is responsible for setting those aspects of Region state
1178 that are mutable after construction.
1181 if ((prop = node.property ("name")) == 0) {
1182 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1186 _name = prop->value();
1188 if ((prop = node.property ("type")) == 0) {
1189 _type = DataType::AUDIO;
1191 _type = DataType(prop->value());
1194 if ((prop = node.property ("start")) != 0) {
1195 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1196 if (val != _start) {
1197 what_changed = Change (what_changed|StartChanged);
1204 if ((prop = node.property ("length")) != 0) {
1205 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1206 if (val != _length) {
1207 what_changed = Change (what_changed|LengthChanged);
1208 _last_length = _length;
1212 _last_length = _length;
1216 if ((prop = node.property ("position")) != 0) {
1217 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1218 if (val != _position) {
1219 what_changed = Change (what_changed|PositionChanged);
1220 _last_position = _position;
1224 _last_position = _position;
1228 if ((prop = node.property ("layer")) != 0) {
1230 x = (layer_t) atoi (prop->value().c_str());
1232 what_changed = Change (what_changed|LayerChanged);
1239 if ((prop = node.property ("sync-position")) != 0) {
1240 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1241 if (val != _sync_position) {
1242 what_changed = Change (what_changed|SyncOffsetChanged);
1243 _sync_position = val;
1246 _sync_position = _start;
1249 if ((prop = node.property ("positional-lock-style")) != 0) {
1250 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1252 if (_positional_lock_style == MusicTime) {
1253 if ((prop = node.property ("bbt-position")) == 0) {
1254 /* missing BBT info, revert to audio time locking */
1255 _positional_lock_style = AudioTime;
1257 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1260 &_bbt_time.ticks) != 3) {
1261 _positional_lock_style = AudioTime;
1267 _positional_lock_style = AudioTime;
1270 /* XXX FIRST EDIT !!! */
1272 /* these 3 properties never change as a result of any editing */
1274 if ((prop = node.property ("ancestral-start")) != 0) {
1275 _ancestral_start = atoi (prop->value());
1277 _ancestral_start = _start;
1280 if ((prop = node.property ("ancestral-length")) != 0) {
1281 _ancestral_length = atoi (prop->value());
1283 _ancestral_length = _length;
1286 if ((prop = node.property ("stretch")) != 0) {
1287 _stretch = atof (prop->value());
1289 /* fix problem with old sessions corrupted by an impossible
1292 if (_stretch == 0.0) {
1299 if ((prop = node.property ("shift")) != 0) {
1300 _shift = atof (prop->value());
1302 /* fix problem with old sessions corrupted by an impossible
1305 if (_shift == 0.0) {
1313 /* note: derived classes set flags */
1318 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1324 if (child->name () == "Extra") {
1325 _extra_xml = new XMLNode (*child);
1331 send_change (what_changed);
1338 Region::set_state (const XMLNode& node)
1340 const XMLProperty *prop;
1341 Change what_changed = Change (0);
1343 /* ID is not allowed to change, ever */
1345 if ((prop = node.property ("id")) == 0) {
1346 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1350 _id = prop->value();
1352 _first_edit = EditChangesNothing;
1354 set_live_state (node, what_changed, true);
1363 _last_length = _length;
1364 _last_position = _position;
1368 Region::thaw (const string& why)
1370 Change what_changed = Change (0);
1373 Glib::Mutex::Lock lm (_lock);
1375 if (_frozen && --_frozen > 0) {
1379 if (_pending_changed) {
1380 what_changed = _pending_changed;
1381 _pending_changed = Change (0);
1385 if (what_changed == Change (0)) {
1389 if (what_changed & LengthChanged) {
1390 if (what_changed & PositionChanged) {
1391 recompute_at_start ();
1393 recompute_at_end ();
1396 StateChanged (what_changed);
1400 Region::send_change (Change what_changed)
1403 Glib::Mutex::Lock lm (_lock);
1405 _pending_changed = Change (_pending_changed|what_changed);
1410 StateChanged (what_changed);
1412 if (!(_flags & DoNotSaveState)) {
1414 /* Try and send a shared_pointer unless this is part of the constructor.
1419 boost::shared_ptr<Region> rptr = shared_from_this();
1420 RegionPropertyChanged (rptr);
1422 /* no shared_ptr available, relax; */
1429 Region::set_last_layer_op (uint64_t when)
1431 _last_layer_op = when;
1435 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1437 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1441 Region::equivalent (boost::shared_ptr<const Region> other) const
1443 return _start == other->_start &&
1444 _position == other->_position &&
1445 _length == other->_length;
1449 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1451 return _start == other->_start &&
1452 _length == other->_length;
1456 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1458 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1462 Region::source_deleted (boost::shared_ptr<Source>)
1469 Region::master_source_names ()
1471 SourceList::iterator i;
1473 vector<string> names;
1474 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1475 names.push_back((*i)->name());
1482 Region::set_master_sources (const SourceList& srcs)
1484 _master_sources = srcs;
1488 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1493 SourceList::const_iterator i;
1494 SourceList::const_iterator io;
1496 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1497 if ((*i)->id() != (*io)->id()) {
1502 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1503 if ((*i)->id() != (*io)->id()) {
1512 Region::source_length(uint32_t n) const
1514 return _sources[n]->length(_position - _start);
1518 Region::verify_length (nframes_t len)
1520 if (source() && (source()->destructive() || source()->length_mutable())) {
1524 nframes_t maxlen = 0;
1526 for (uint32_t n=0; n < _sources.size(); ++n) {
1527 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1530 len = min (len, maxlen);
1536 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1538 if (source() && (source()->destructive() || source()->length_mutable())) {
1542 nframes_t maxlen = 0;
1544 for (uint32_t n=0; n < _sources.size(); ++n) {
1545 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1548 new_length = min (new_length, maxlen);
1554 Region::verify_start (nframes_t pos)
1556 if (source() && (source()->destructive() || source()->length_mutable())) {
1560 for (uint32_t n=0; n < _sources.size(); ++n) {
1561 if (pos > source_length(n) - _length) {
1569 Region::verify_start_mutable (nframes_t& new_start)
1571 if (source() && (source()->destructive() || source()->length_mutable())) {
1575 for (uint32_t n=0; n < _sources.size(); ++n) {
1576 if (new_start > source_length(n) - _length) {
1577 new_start = source_length(n) - _length;
1583 boost::shared_ptr<Region>
1584 Region::get_parent() const
1586 boost::shared_ptr<Playlist> pl (playlist());
1589 boost::shared_ptr<Region> r;
1590 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1592 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1593 return boost::static_pointer_cast<Region> (r);
1597 return boost::shared_ptr<Region>();
1601 Region::apply (Filter& filter)
1603 return filter.run (shared_from_this());
1608 Region::invalidate_transients ()
1610 _valid_transients = false;
1611 _transients.clear ();
1616 Region::use_sources (SourceList const & s)
1618 set<boost::shared_ptr<Source> > unique_srcs;
1620 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1621 _sources.push_back (*i);
1622 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));
1623 unique_srcs.insert (*i);
1626 for (SourceList::const_iterator i = s.begin(); i != s.end(); ++i) {
1627 _master_sources.push_back (*i);
1628 if (unique_srcs.find (*i) == unique_srcs.end()) {
1629 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));