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>
45 using namespace ARDOUR;
48 Change Region::FadeChanged = ARDOUR::new_change ();
49 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
50 Change Region::MuteChanged = ARDOUR::new_change ();
51 Change Region::OpacityChanged = ARDOUR::new_change ();
52 Change Region::LockChanged = ARDOUR::new_change ();
53 Change Region::LayerChanged = ARDOUR::new_change ();
54 Change Region::HiddenChanged = ARDOUR::new_change ();
56 sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
58 /* derived-from-derived constructor (no sources in constructor) */
59 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
60 : SessionObject(s, name)
67 , _positional_lock_style(AudioTime)
68 , _sync_position(_start)
70 , _first_edit(EditChangesNothing)
74 , _pending_changed(Change (0))
77 /* no sources at this point */
80 /** Basic Region constructor (single source) */
81 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
82 : SessionObject(src->session(), name)
89 , _positional_lock_style(AudioTime)
90 , _sync_position(_start)
92 , _first_edit(EditChangesNothing)
94 , _ancestral_start (start)
95 , _ancestral_length (length)
98 , _valid_transients(false)
100 , _pending_changed(Change (0))
104 _sources.push_back (src);
105 _master_sources.push_back (src);
107 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
109 assert(_sources.size() > 0);
110 _positional_lock_style = AudioTime;
113 /** Basic Region constructor (many sources) */
114 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
115 : SessionObject(srcs.front()->session(), name)
122 , _positional_lock_style(AudioTime)
123 , _sync_position(_start)
125 , _first_edit(EditChangesNothing)
128 , _read_data_count(0)
129 , _pending_changed(Change (0))
133 set<boost::shared_ptr<Source> > unique_srcs;
135 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
136 _sources.push_back (*i);
137 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
138 unique_srcs.insert (*i);
141 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
142 _master_sources.push_back (*i);
143 if (unique_srcs.find (*i) == unique_srcs.end()) {
144 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
148 assert(_sources.size() > 0);
151 /** Create a new Region from part of an existing one */
152 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
153 : SessionObject(other->session(), name)
154 , _type(other->data_type())
155 , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
156 , _start(other->_start + offset)
160 , _positional_lock_style(other->_positional_lock_style)
161 , _sync_position(_start)
163 , _first_edit(EditChangesNothing)
165 , _ancestral_start (other->_ancestral_start + offset)
166 , _ancestral_length (length)
169 , _valid_transients(false)
170 , _read_data_count(0)
171 , _pending_changed(Change (0))
174 if (other->_sync_position < offset)
175 _sync_position = other->_sync_position;
177 set<boost::shared_ptr<Source> > unique_srcs;
179 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
180 _sources.push_back (*i);
181 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
182 unique_srcs.insert (*i);
185 if (other->_sync_position < offset) {
186 _sync_position = other->_sync_position;
190 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
191 if (unique_srcs.find (*i) == unique_srcs.end()) {
192 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
194 _master_sources.push_back (*i);
197 assert(_sources.size() > 0);
200 /** Pure copy constructor */
201 Region::Region (boost::shared_ptr<const Region> other)
202 : SessionObject(other->session(), other->name())
203 , _type(other->data_type())
204 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
205 , _start(other->_start)
206 , _length(other->_length)
207 , _position(other->_position)
208 , _last_position(other->_last_position)
209 , _positional_lock_style(other->_positional_lock_style)
210 , _sync_position(other->_sync_position)
211 , _layer(other->_layer)
212 , _first_edit(EditChangesID)
214 , _ancestral_start (other->_ancestral_start)
215 , _ancestral_length (other->_ancestral_length)
218 , _valid_transients(false)
219 , _read_data_count(0)
220 , _pending_changed(Change(0))
221 , _last_layer_op(other->_last_layer_op)
223 other->_first_edit = EditChangesName;
225 if (other->_extra_xml) {
226 _extra_xml = new XMLNode (*other->_extra_xml);
231 set<boost::shared_ptr<Source> > unique_srcs;
233 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
234 _sources.push_back (*i);
235 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
236 unique_srcs.insert (*i);
239 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
240 _master_sources.push_back (*i);
241 if (unique_srcs.find (*i) == unique_srcs.end()) {
242 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
246 assert(_sources.size() > 0);
249 Region::Region (const SourceList& srcs, const XMLNode& node)
250 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
251 , _type(DataType::NIL) // to be loaded from XML
257 , _positional_lock_style(AudioTime)
258 , _sync_position(_start)
260 , _first_edit(EditChangesNothing)
263 , _read_data_count(0)
264 , _pending_changed(Change(0))
267 set<boost::shared_ptr<Source> > unique_srcs;
269 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
270 _sources.push_back (*i);
271 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
272 unique_srcs.insert (*i);
275 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
276 _master_sources.push_back (*i);
277 if (unique_srcs.find (*i) == unique_srcs.end()) {
278 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
282 if (set_state (node)) {
283 throw failed_constructor();
286 assert(_type != DataType::NIL);
287 assert(_sources.size() > 0);
290 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
291 : SessionObject(src->session(), X_("error: XML did not reset this"))
292 , _type(DataType::NIL)
298 , _positional_lock_style(AudioTime)
299 , _sync_position(_start)
301 , _first_edit(EditChangesNothing)
304 , _read_data_count(0)
305 , _pending_changed(Change(0))
308 _sources.push_back (src);
310 if (set_state (node)) {
311 throw failed_constructor();
314 assert(_type != DataType::NIL);
315 assert(_sources.size() > 0);
320 boost::shared_ptr<Playlist> pl (playlist());
323 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
324 (*i)->remove_playlist (pl);
326 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
327 (*i)->remove_playlist (pl);
332 GoingAway (); /* EMIT SIGNAL */
336 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
338 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
340 boost::shared_ptr<Playlist> pl (wpl.lock());
342 if (old_playlist == pl) {
350 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
351 (*i)->remove_playlist (_playlist);
352 (*i)->add_playlist (pl);
354 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
355 (*i)->remove_playlist (_playlist);
356 (*i)->add_playlist (pl);
359 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
360 (*i)->add_playlist (pl);
362 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
363 (*i)->add_playlist (pl);
368 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
369 (*i)->remove_playlist (old_playlist);
371 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
372 (*i)->remove_playlist (old_playlist);
379 Region::set_name (const std::string& str)
382 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
383 assert(_name == str);
384 send_change (ARDOUR::NameChanged);
391 Region::set_length (nframes_t len, void *src)
393 //cerr << "Region::set_length() len = " << len << endl;
394 if (_flags & Locked) {
398 if (_length != len && len != 0) {
400 /* check that the current _position wouldn't make the new
404 if (max_frames - len < _position) {
408 if (!verify_length (len)) {
413 _last_length = _length;
416 _flags = Region::Flag (_flags & ~WholeFile);
420 invalidate_transients ();
426 send_change (LengthChanged);
431 Region::maybe_uncopy ()
436 Region::first_edit ()
438 boost::shared_ptr<Playlist> pl (playlist());
440 if (_first_edit != EditChangesNothing && pl) {
442 _name = pl->session().new_region_name (_name);
443 _first_edit = EditChangesNothing;
445 send_change (ARDOUR::NameChanged);
446 RegionFactory::CheckNewRegion (shared_from_this());
451 Region::at_natural_position () const
453 boost::shared_ptr<Playlist> pl (playlist());
459 boost::shared_ptr<Region> whole_file_region = get_parent();
461 if (whole_file_region) {
462 if (_position == whole_file_region->position() + _start) {
471 Region::move_to_natural_position (void *src)
473 boost::shared_ptr<Playlist> pl (playlist());
479 boost::shared_ptr<Region> whole_file_region = get_parent();
481 if (whole_file_region) {
482 set_position (whole_file_region->position() + _start, src);
487 Region::special_set_position (nframes_t pos)
489 /* this is used when creating a whole file region as
490 a way to store its "natural" or "captured" position.
493 _position = _position;
498 Region::set_position_lock_style (PositionLockStyle ps)
500 boost::shared_ptr<Playlist> pl (playlist());
506 _positional_lock_style = ps;
508 if (_positional_lock_style == MusicTime) {
509 pl->session().tempo_map().bbt_time (_position, _bbt_time);
515 Region::update_position_after_tempo_map_change ()
517 boost::shared_ptr<Playlist> pl (playlist());
519 if (!pl || _positional_lock_style != MusicTime) {
523 TempoMap& map (pl->session().tempo_map());
524 nframes_t pos = map.frame_time (_bbt_time);
525 set_position_internal (pos, false);
529 Region::set_position (nframes_t pos, void *src)
535 set_position_internal (pos, true);
539 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
541 if (_position != pos) {
542 _last_position = _position;
545 /* check that the new _position wouldn't make the current
546 length impossible - if so, change the length.
548 XXX is this the right thing to do?
551 if (max_frames - _length < _position) {
552 _last_length = _length;
553 _length = max_frames - _position;
556 if (allow_bbt_recompute) {
557 recompute_position_from_lock_style ();
560 invalidate_transients ();
563 /* do this even if the position is the same. this helps out
564 a GUI that has moved its representation already.
567 send_change (PositionChanged);
571 Region::set_position_on_top (nframes_t pos, void *src)
573 if (_flags & Locked) {
577 if (_position != pos) {
578 _last_position = _position;
582 boost::shared_ptr<Playlist> pl (playlist());
585 pl->raise_region_to_top (shared_from_this ());
588 /* do this even if the position is the same. this helps out
589 a GUI that has moved its representation already.
592 send_change (PositionChanged);
596 Region::recompute_position_from_lock_style ()
598 if (_positional_lock_style == MusicTime) {
599 boost::shared_ptr<Playlist> pl (playlist());
601 pl->session().tempo_map().bbt_time (_position, _bbt_time);
607 Region::nudge_position (nframes64_t n, void *src)
609 if (_flags & Locked) {
617 _last_position = _position;
620 if (_position > max_frames - n) {
621 _position = max_frames;
626 if (_position < (nframes_t) -n) {
633 send_change (PositionChanged);
637 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
639 _ancestral_length = l;
640 _ancestral_start = s;
646 Region::set_start (nframes_t pos, void *src)
648 if (_flags & (Locked|PositionLocked)) {
651 /* This just sets the start, nothing else. It effectively shifts
652 the contents of the Region within the overall extent of the Source,
653 without changing the Region's position or length
658 if (!verify_start (pos)) {
663 _flags = Region::Flag (_flags & ~WholeFile);
665 invalidate_transients ();
667 send_change (StartChanged);
672 Region::trim_start (nframes_t new_position, void *src)
674 if (_flags & (Locked|PositionLocked)) {
680 if (new_position > _position) {
681 start_shift = new_position - _position;
683 start_shift = -(_position - new_position);
686 if (start_shift > 0) {
688 if (_start > max_frames - start_shift) {
689 new_start = max_frames;
691 new_start = _start + start_shift;
694 if (!verify_start (new_start)) {
698 } else if (start_shift < 0) {
700 if (_start < (nframes_t) -start_shift) {
703 new_start = _start + start_shift;
709 if (new_start == _start) {
714 _flags = Region::Flag (_flags & ~WholeFile);
717 send_change (StartChanged);
721 Region::trim_front (nframes_t new_position, void *src)
723 if (_flags & Locked) {
727 nframes_t end = last_frame();
728 nframes_t source_zero;
730 if (_position > _start) {
731 source_zero = _position - _start;
733 source_zero = 0; // its actually negative, but this will work for us
736 if (new_position < end) { /* can't trim it zero or negative length */
740 /* can't trim it back passed where source position zero is located */
742 new_position = max (new_position, source_zero);
745 if (new_position > _position) {
746 newlen = _length - (new_position - _position);
748 newlen = _length + (_position - new_position);
751 trim_to_internal (new_position, newlen, src);
753 recompute_at_start ();
759 Region::trim_end (nframes_t new_endpoint, void *src)
761 if (_flags & Locked) {
765 if (new_endpoint > _position) {
766 trim_to_internal (_position, new_endpoint - _position, this);
774 Region::trim_to (nframes_t position, nframes_t length, void *src)
776 if (_flags & Locked) {
780 trim_to_internal (position, length, src);
783 recompute_at_start ();
789 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
794 if (_flags & Locked) {
798 if (position > _position) {
799 start_shift = position - _position;
801 start_shift = -(_position - position);
804 if (start_shift > 0) {
806 if (_start > max_frames - start_shift) {
807 new_start = max_frames;
809 new_start = _start + start_shift;
813 } else if (start_shift < 0) {
815 if (_start < (nframes_t) -start_shift) {
818 new_start = _start + start_shift;
824 if (!verify_start_and_length (new_start, length)) {
828 Change what_changed = Change (0);
830 if (_start != new_start) {
832 what_changed = Change (what_changed|StartChanged);
834 if (_length != length) {
836 _last_length = _length;
839 what_changed = Change (what_changed|LengthChanged);
841 if (_position != position) {
843 _last_position = _position;
845 _position = position;
846 what_changed = Change (what_changed|PositionChanged);
849 _flags = Region::Flag (_flags & ~WholeFile);
851 if (what_changed & (StartChanged|LengthChanged)) {
856 send_change (what_changed);
861 Region::set_hidden (bool yn)
863 if (hidden() != yn) {
866 _flags = Flag (_flags|Hidden);
868 _flags = Flag (_flags & ~Hidden);
871 send_change (HiddenChanged);
876 Region::set_muted (bool yn)
881 _flags = Flag (_flags|Muted);
883 _flags = Flag (_flags & ~Muted);
886 send_change (MuteChanged);
891 Region::set_opaque (bool yn)
893 if (opaque() != yn) {
895 _flags = Flag (_flags|Opaque);
897 _flags = Flag (_flags & ~Opaque);
899 send_change (OpacityChanged);
904 Region::set_locked (bool yn)
906 if (locked() != yn) {
908 _flags = Flag (_flags|Locked);
910 _flags = Flag (_flags & ~Locked);
912 send_change (LockChanged);
917 Region::set_position_locked (bool yn)
919 if (position_locked() != yn) {
921 _flags = Flag (_flags|PositionLocked);
923 _flags = Flag (_flags & ~PositionLocked);
925 send_change (LockChanged);
930 Region::set_sync_position (nframes_t absolute_pos)
934 file_pos = _start + (absolute_pos - _position);
936 if (file_pos != _sync_position) {
938 _sync_position = file_pos;
939 _flags = Flag (_flags|SyncMarked);
944 send_change (SyncOffsetChanged);
949 Region::clear_sync_position ()
951 if (_flags & SyncMarked) {
952 _flags = Flag (_flags & ~SyncMarked);
957 send_change (SyncOffsetChanged);
962 Region::sync_offset (int& dir) const
964 /* returns the sync point relative the first frame of the region */
966 if (_flags & SyncMarked) {
967 if (_sync_position > _start) {
969 return _sync_position - _start;
972 return _start - _sync_position;
981 Region::adjust_to_sync (nframes_t pos)
984 nframes_t offset = sync_offset (sync_dir);
986 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
995 if (max_frames - pos > offset) {
1004 Region::sync_position() const
1006 if (_flags & SyncMarked) {
1007 return _sync_position;
1016 boost::shared_ptr<Playlist> pl (playlist());
1018 pl->raise_region (shared_from_this ());
1025 boost::shared_ptr<Playlist> pl (playlist());
1027 pl->lower_region (shared_from_this ());
1033 Region::raise_to_top ()
1035 boost::shared_ptr<Playlist> pl (playlist());
1037 pl->raise_region_to_top (shared_from_this());
1042 Region::lower_to_bottom ()
1044 boost::shared_ptr<Playlist> pl (playlist());
1046 pl->lower_region_to_bottom (shared_from_this());
1051 Region::set_layer (layer_t l)
1056 send_change (LayerChanged);
1061 Region::state (bool full_state)
1063 XMLNode *node = new XMLNode ("Region");
1065 const char* fe = NULL;
1067 _id.print (buf, sizeof (buf));
1068 node->add_property ("id", buf);
1069 node->add_property ("name", _name);
1070 node->add_property ("type", _type.to_string());
1071 snprintf (buf, sizeof (buf), "%u", _start);
1072 node->add_property ("start", buf);
1073 snprintf (buf, sizeof (buf), "%u", _length);
1074 node->add_property ("length", buf);
1075 snprintf (buf, sizeof (buf), "%u", _position);
1076 node->add_property ("position", buf);
1077 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1078 node->add_property ("ancestral-start", buf);
1079 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1080 node->add_property ("ancestral-length", buf);
1081 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1082 node->add_property ("stretch", buf);
1083 snprintf (buf, sizeof (buf), "%.12g", _shift);
1084 node->add_property ("shift", buf);
1086 switch (_first_edit) {
1087 case EditChangesNothing:
1090 case EditChangesName:
1096 default: /* should be unreachable but makes g++ happy */
1101 node->add_property ("first-edit", fe);
1103 /* note: flags are stored by derived classes */
1105 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1106 node->add_property ("layer", buf);
1107 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1108 node->add_property ("sync-position", buf);
1110 if (_positional_lock_style != AudioTime) {
1111 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1114 node->add_property ("bbt-position", str.str());
1121 Region::get_state ()
1123 return state (true);
1127 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1129 const XMLNodeList& nlist = node.children();
1130 const XMLProperty *prop;
1133 /* this is responsible for setting those aspects of Region state
1134 that are mutable after construction.
1137 if ((prop = node.property ("name")) == 0) {
1138 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1142 _name = prop->value();
1144 if ((prop = node.property ("type")) == 0) {
1145 _type = DataType::AUDIO;
1147 _type = DataType(prop->value());
1150 if ((prop = node.property ("start")) != 0) {
1151 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1152 if (val != _start) {
1153 what_changed = Change (what_changed|StartChanged);
1160 if ((prop = node.property ("length")) != 0) {
1161 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1162 if (val != _length) {
1163 what_changed = Change (what_changed|LengthChanged);
1164 _last_length = _length;
1168 _last_length = _length;
1172 if ((prop = node.property ("position")) != 0) {
1173 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1174 if (val != _position) {
1175 what_changed = Change (what_changed|PositionChanged);
1176 _last_position = _position;
1180 _last_position = _position;
1184 if ((prop = node.property ("layer")) != 0) {
1186 x = (layer_t) atoi (prop->value().c_str());
1188 what_changed = Change (what_changed|LayerChanged);
1195 if ((prop = node.property ("sync-position")) != 0) {
1196 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1197 if (val != _sync_position) {
1198 what_changed = Change (what_changed|SyncOffsetChanged);
1199 _sync_position = val;
1202 _sync_position = _start;
1205 if ((prop = node.property ("positional-lock-style")) != 0) {
1206 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1208 if (_positional_lock_style == MusicTime) {
1209 if ((prop = node.property ("bbt-position")) == 0) {
1210 /* missing BBT info, revert to audio time locking */
1211 _positional_lock_style = AudioTime;
1213 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1216 &_bbt_time.ticks) != 3) {
1217 _positional_lock_style = AudioTime;
1223 _positional_lock_style = AudioTime;
1226 /* XXX FIRST EDIT !!! */
1228 /* these 3 properties never change as a result of any editing */
1230 if ((prop = node.property ("ancestral-start")) != 0) {
1231 _ancestral_start = atoi (prop->value());
1233 _ancestral_start = _start;
1236 if ((prop = node.property ("ancestral-length")) != 0) {
1237 _ancestral_length = atoi (prop->value());
1239 _ancestral_length = _length;
1242 if ((prop = node.property ("stretch")) != 0) {
1243 _stretch = atof (prop->value());
1248 if ((prop = node.property ("shift")) != 0) {
1249 _shift = atof (prop->value());
1254 /* note: derived classes set flags */
1261 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1267 if (child->name () == "extra") {
1268 _extra_xml = new XMLNode (*child);
1274 send_change (what_changed);
1281 Region::set_state (const XMLNode& node)
1283 const XMLProperty *prop;
1284 Change what_changed = Change (0);
1286 /* ID is not allowed to change, ever */
1288 if ((prop = node.property ("id")) == 0) {
1289 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1293 _id = prop->value();
1295 _first_edit = EditChangesNothing;
1297 set_live_state (node, what_changed, true);
1306 _last_length = _length;
1307 _last_position = _position;
1311 Region::thaw (const string& why)
1313 Change what_changed = Change (0);
1316 Glib::Mutex::Lock lm (_lock);
1318 if (_frozen && --_frozen > 0) {
1322 if (_pending_changed) {
1323 what_changed = _pending_changed;
1324 _pending_changed = Change (0);
1328 if (what_changed == Change (0)) {
1332 if (what_changed & LengthChanged) {
1333 if (what_changed & PositionChanged) {
1334 recompute_at_start ();
1336 recompute_at_end ();
1339 StateChanged (what_changed);
1343 Region::send_change (Change what_changed)
1346 Glib::Mutex::Lock lm (_lock);
1348 _pending_changed = Change (_pending_changed|what_changed);
1353 StateChanged (what_changed);
1355 if (!(_flags & DoNotSaveState)) {
1357 /* Try and send a shared_pointer unless this is part of the constructor.
1362 boost::shared_ptr<Region> rptr = shared_from_this();
1363 RegionPropertyChanged (rptr);
1365 /* no shared_ptr available, relax; */
1372 Region::set_last_layer_op (uint64_t when)
1374 _last_layer_op = when;
1378 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1380 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1384 Region::equivalent (boost::shared_ptr<const Region> other) const
1386 return _start == other->_start &&
1387 _position == other->_position &&
1388 _length == other->_length;
1392 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1394 return _start == other->_start &&
1395 _length == other->_length;
1399 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1401 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1405 Region::source_deleted (boost::shared_ptr<Source>)
1412 Region::master_source_names ()
1414 SourceList::iterator i;
1416 vector<string> names;
1417 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1418 names.push_back((*i)->name());
1425 Region::set_master_sources (const SourceList& srcs)
1427 _master_sources = srcs;
1431 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1436 SourceList::const_iterator i;
1437 SourceList::const_iterator io;
1439 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1440 if ((*i)->id() != (*io)->id()) {
1445 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1446 if ((*i)->id() != (*io)->id()) {
1455 Region::verify_length (nframes_t len)
1457 if (source() && (source()->destructive() || source()->length_mutable())) {
1461 nframes_t maxlen = 0;
1463 for (uint32_t n=0; n < _sources.size(); ++n) {
1464 maxlen = max (maxlen, _sources[n]->length() - _start);
1467 len = min (len, maxlen);
1473 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1475 if (source() && (source()->destructive() || source()->length_mutable())) {
1479 nframes_t maxlen = 0;
1481 for (uint32_t n=0; n < _sources.size(); ++n) {
1482 maxlen = max (maxlen, _sources[n]->length() - new_start);
1485 new_length = min (new_length, maxlen);
1491 Region::verify_start (nframes_t pos)
1493 if (source() && (source()->destructive() || source()->length_mutable())) {
1497 for (uint32_t n=0; n < _sources.size(); ++n) {
1498 if (pos > _sources[n]->length() - _length) {
1506 Region::verify_start_mutable (nframes_t& new_start)
1508 if (source() && (source()->destructive() || source()->length_mutable())) {
1512 for (uint32_t n=0; n < _sources.size(); ++n) {
1513 if (new_start > _sources[n]->length() - _length) {
1514 new_start = _sources[n]->length() - _length;
1520 boost::shared_ptr<Region>
1521 Region::get_parent() const
1523 boost::shared_ptr<Playlist> pl (playlist());
1526 boost::shared_ptr<Region> r;
1527 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1529 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1530 return boost::static_pointer_cast<Region> (r);
1534 return boost::shared_ptr<Region>();
1538 Region::apply (Filter& filter)
1540 return filter.run (shared_from_this());
1545 Region::invalidate_transients ()
1547 _valid_transients = false;
1548 _transients.clear ();