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 ();
57 /* derived-from-derived constructor (no sources in constructor) */
58 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
59 : Automatable(s, name)
66 , _positional_lock_style(AudioTime)
67 , _sync_position(_start)
69 , _first_edit(EditChangesNothing)
73 , _pending_changed(Change (0))
76 /* no sources at this point */
79 /** Basic Region constructor (single source) */
80 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
81 : Automatable(src->session(), name)
88 , _positional_lock_style(AudioTime)
89 , _sync_position(_start)
91 , _first_edit(EditChangesNothing)
93 , _ancestral_start (start)
94 , _ancestral_length (length)
97 , _valid_transients(false)
99 , _pending_changed(Change (0))
103 _sources.push_back (src);
104 _master_sources.push_back (src);
106 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
108 assert(_sources.size() > 0);
109 _positional_lock_style = AudioTime;
112 /** Basic Region constructor (many sources) */
113 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
114 : Automatable(srcs.front()->session(), name)
121 , _positional_lock_style(AudioTime)
122 , _sync_position(_start)
124 , _first_edit(EditChangesNothing)
127 , _read_data_count(0)
128 , _pending_changed(Change (0))
132 set<boost::shared_ptr<Source> > unique_srcs;
134 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
135 _sources.push_back (*i);
136 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
137 unique_srcs.insert (*i);
140 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
141 _master_sources.push_back (*i);
142 if (unique_srcs.find (*i) == unique_srcs.end()) {
143 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
147 assert(_sources.size() > 0);
150 /** Create a new Region from part of an existing one */
151 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
152 : Automatable(other->session(), name)
153 , _type(other->data_type())
154 , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
155 , _start(other->_start + offset)
159 , _positional_lock_style(other->_positional_lock_style)
160 , _sync_position(_start)
162 , _first_edit(EditChangesNothing)
164 , _ancestral_start (other->_ancestral_start + offset)
165 , _ancestral_length (length)
168 , _valid_transients(false)
169 , _read_data_count(0)
170 , _pending_changed(Change (0))
173 if (other->_sync_position < offset)
174 _sync_position = other->_sync_position;
176 set<boost::shared_ptr<Source> > unique_srcs;
178 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
179 _sources.push_back (*i);
180 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
181 unique_srcs.insert (*i);
184 if (other->_sync_position < offset) {
185 _sync_position = other->_sync_position;
188 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
189 if (unique_srcs.find (*i) == unique_srcs.end()) {
190 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
192 _master_sources.push_back (*i);
195 assert(_sources.size() > 0);
198 /** Pure copy constructor */
199 Region::Region (boost::shared_ptr<const Region> other)
200 : Automatable(other->session(), other->name())
201 , _type(other->data_type())
202 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
203 , _start(other->_start)
204 , _length(other->_length)
205 , _position(other->_position)
206 , _last_position(other->_last_position)
207 , _positional_lock_style(other->_positional_lock_style)
208 , _sync_position(other->_sync_position)
209 , _layer(other->_layer)
210 , _first_edit(EditChangesID)
212 , _ancestral_start (_start)
213 , _ancestral_length (_length)
216 , _valid_transients(false)
217 , _read_data_count(0)
218 , _pending_changed(Change(0))
219 , _last_layer_op(other->_last_layer_op)
221 other->_first_edit = EditChangesName;
223 if (other->_extra_xml) {
224 _extra_xml = new XMLNode (*other->_extra_xml);
229 set<boost::shared_ptr<Source> > unique_srcs;
231 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
232 _sources.push_back (*i);
233 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
234 unique_srcs.insert (*i);
237 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
238 _master_sources.push_back (*i);
239 if (unique_srcs.find (*i) == unique_srcs.end()) {
240 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
244 assert(_sources.size() > 0);
247 Region::Region (const SourceList& srcs, const XMLNode& node)
248 : Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
249 , _type(DataType::NIL) // to be loaded from XML
255 , _positional_lock_style(AudioTime)
256 , _sync_position(_start)
258 , _first_edit(EditChangesNothing)
261 , _read_data_count(0)
262 , _pending_changed(Change(0))
265 set<boost::shared_ptr<Source> > unique_srcs;
267 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
268 _sources.push_back (*i);
269 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
270 unique_srcs.insert (*i);
273 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
274 _master_sources.push_back (*i);
275 if (unique_srcs.find (*i) == unique_srcs.end()) {
276 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
280 if (set_state (node)) {
281 throw failed_constructor();
284 assert(_type != DataType::NIL);
285 assert(_sources.size() > 0);
288 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
289 : Automatable(src->session(), X_("error: XML did not reset this"))
290 , _type(DataType::NIL)
296 , _positional_lock_style(AudioTime)
297 , _sync_position(_start)
299 , _first_edit(EditChangesNothing)
302 , _read_data_count(0)
303 , _pending_changed(Change(0))
306 _sources.push_back (src);
308 if (set_state (node)) {
309 throw failed_constructor();
312 assert(_type != DataType::NIL);
313 assert(_sources.size() > 0);
318 boost::shared_ptr<Playlist> pl (playlist());
321 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
322 (*i)->remove_playlist (pl);
324 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
325 (*i)->remove_playlist (pl);
330 GoingAway (); /* EMIT SIGNAL */
334 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
336 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
338 boost::shared_ptr<Playlist> pl (wpl.lock());
340 if (old_playlist == pl) {
348 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
349 (*i)->remove_playlist (_playlist);
350 (*i)->add_playlist (pl);
352 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
353 (*i)->remove_playlist (_playlist);
354 (*i)->add_playlist (pl);
357 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
358 (*i)->add_playlist (pl);
360 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
361 (*i)->add_playlist (pl);
366 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
367 (*i)->remove_playlist (old_playlist);
369 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
370 (*i)->remove_playlist (old_playlist);
377 Region::set_name (const std::string& str)
380 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
381 assert(_name == str);
382 send_change (ARDOUR::NameChanged);
389 Region::set_length (nframes_t len, void *src)
391 if (_flags & Locked) {
395 if (_length != len && len != 0) {
397 /* check that the current _position wouldn't make the new
401 if (max_frames - len < _position) {
405 if (!verify_length (len)) {
410 _last_length = _length;
413 _flags = Region::Flag (_flags & ~WholeFile);
417 invalidate_transients ();
423 send_change (LengthChanged);
428 Region::maybe_uncopy ()
433 Region::first_edit ()
435 boost::shared_ptr<Playlist> pl (playlist());
437 if (_first_edit != EditChangesNothing && pl) {
439 _name = pl->session().new_region_name (_name);
440 _first_edit = EditChangesNothing;
442 send_change (ARDOUR::NameChanged);
443 RegionFactory::CheckNewRegion (shared_from_this());
448 Region::at_natural_position () const
450 boost::shared_ptr<Playlist> pl (playlist());
456 boost::shared_ptr<Region> whole_file_region = get_parent();
458 if (whole_file_region) {
459 if (_position == whole_file_region->position() + _start) {
468 Region::move_to_natural_position (void *src)
470 boost::shared_ptr<Playlist> pl (playlist());
476 boost::shared_ptr<Region> whole_file_region = get_parent();
478 if (whole_file_region) {
479 set_position (whole_file_region->position() + _start, src);
484 Region::special_set_position (nframes_t pos)
486 /* this is used when creating a whole file region as
487 a way to store its "natural" or "captured" position.
490 _position = _position;
495 Region::set_position_lock_style (PositionLockStyle ps)
497 boost::shared_ptr<Playlist> pl (playlist());
503 _positional_lock_style = ps;
505 if (_positional_lock_style == MusicTime) {
506 pl->session().tempo_map().bbt_time (_position, _bbt_time);
512 Region::update_position_after_tempo_map_change ()
514 boost::shared_ptr<Playlist> pl (playlist());
516 if (!pl || _positional_lock_style != MusicTime) {
520 TempoMap& map (pl->session().tempo_map());
521 nframes_t pos = map.frame_time (_bbt_time);
522 set_position_internal (pos, false);
526 Region::set_position (nframes_t pos, void *src)
532 set_position_internal (pos, true);
536 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
538 if (_position != pos) {
539 _last_position = _position;
542 /* check that the new _position wouldn't make the current
543 length impossible - if so, change the length.
545 XXX is this the right thing to do?
548 if (max_frames - _length < _position) {
549 _last_length = _length;
550 _length = max_frames - _position;
553 if (allow_bbt_recompute) {
554 recompute_position_from_lock_style ();
557 invalidate_transients ();
560 /* do this even if the position is the same. this helps out
561 a GUI that has moved its representation already.
564 send_change (PositionChanged);
568 Region::set_position_on_top (nframes_t pos, void *src)
570 if (_flags & Locked) {
574 if (_position != pos) {
575 _last_position = _position;
579 boost::shared_ptr<Playlist> pl (playlist());
582 pl->raise_region_to_top (shared_from_this ());
585 /* do this even if the position is the same. this helps out
586 a GUI that has moved its representation already.
589 send_change (PositionChanged);
593 Region::recompute_position_from_lock_style ()
595 if (_positional_lock_style == MusicTime) {
596 boost::shared_ptr<Playlist> pl (playlist());
598 pl->session().tempo_map().bbt_time (_position, _bbt_time);
604 Region::nudge_position (nframes64_t n, void *src)
606 if (_flags & Locked) {
614 _last_position = _position;
617 if (_position > max_frames - n) {
618 _position = max_frames;
623 if (_position < (nframes_t) -n) {
630 send_change (PositionChanged);
634 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
636 _ancestral_length = l;
637 _ancestral_start = s;
643 Region::set_start (nframes_t pos, void *src)
645 if (_flags & (Locked|PositionLocked)) {
648 /* This just sets the start, nothing else. It effectively shifts
649 the contents of the Region within the overall extent of the Source,
650 without changing the Region's position or length
655 if (!verify_start (pos)) {
660 _flags = Region::Flag (_flags & ~WholeFile);
662 invalidate_transients ();
664 send_change (StartChanged);
669 Region::trim_start (nframes_t new_position, void *src)
671 if (_flags & (Locked|PositionLocked)) {
677 if (new_position > _position) {
678 start_shift = new_position - _position;
680 start_shift = -(_position - new_position);
683 if (start_shift > 0) {
685 if (_start > max_frames - start_shift) {
686 new_start = max_frames;
688 new_start = _start + start_shift;
691 if (!verify_start (new_start)) {
695 } else if (start_shift < 0) {
697 if (_start < (nframes_t) -start_shift) {
700 new_start = _start + start_shift;
706 if (new_start == _start) {
711 _flags = Region::Flag (_flags & ~WholeFile);
714 send_change (StartChanged);
718 Region::trim_front (nframes_t new_position, void *src)
720 if (_flags & Locked) {
724 nframes_t end = last_frame();
725 nframes_t source_zero;
727 if (_position > _start) {
728 source_zero = _position - _start;
730 source_zero = 0; // its actually negative, but this will work for us
733 if (new_position < end) { /* can't trim it zero or negative length */
737 /* can't trim it back passed where source position zero is located */
739 new_position = max (new_position, source_zero);
742 if (new_position > _position) {
743 newlen = _length - (new_position - _position);
745 newlen = _length + (_position - new_position);
748 trim_to_internal (new_position, newlen, src);
750 recompute_at_start ();
756 Region::trim_end (nframes_t new_endpoint, void *src)
758 if (_flags & Locked) {
762 if (new_endpoint > _position) {
763 trim_to_internal (_position, new_endpoint - _position, this);
771 Region::trim_to (nframes_t position, nframes_t length, void *src)
773 if (_flags & Locked) {
777 trim_to_internal (position, length, src);
780 recompute_at_start ();
786 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
791 if (_flags & Locked) {
795 if (position > _position) {
796 start_shift = position - _position;
798 start_shift = -(_position - position);
801 if (start_shift > 0) {
803 if (_start > max_frames - start_shift) {
804 new_start = max_frames;
806 new_start = _start + start_shift;
810 } else if (start_shift < 0) {
812 if (_start < (nframes_t) -start_shift) {
815 new_start = _start + start_shift;
821 if (!verify_start_and_length (new_start, length)) {
825 Change what_changed = Change (0);
827 if (_start != new_start) {
829 what_changed = Change (what_changed|StartChanged);
831 if (_length != length) {
833 _last_length = _length;
836 what_changed = Change (what_changed|LengthChanged);
838 if (_position != position) {
840 _last_position = _position;
842 _position = position;
843 what_changed = Change (what_changed|PositionChanged);
846 _flags = Region::Flag (_flags & ~WholeFile);
848 if (what_changed & (StartChanged|LengthChanged)) {
853 send_change (what_changed);
858 Region::set_hidden (bool yn)
860 if (hidden() != yn) {
863 _flags = Flag (_flags|Hidden);
865 _flags = Flag (_flags & ~Hidden);
868 send_change (HiddenChanged);
873 Region::set_muted (bool yn)
878 _flags = Flag (_flags|Muted);
880 _flags = Flag (_flags & ~Muted);
883 send_change (MuteChanged);
888 Region::set_opaque (bool yn)
890 if (opaque() != yn) {
892 _flags = Flag (_flags|Opaque);
894 _flags = Flag (_flags & ~Opaque);
896 send_change (OpacityChanged);
901 Region::set_locked (bool yn)
903 if (locked() != yn) {
905 _flags = Flag (_flags|Locked);
907 _flags = Flag (_flags & ~Locked);
909 send_change (LockChanged);
914 Region::set_position_locked (bool yn)
916 if (position_locked() != yn) {
918 _flags = Flag (_flags|PositionLocked);
920 _flags = Flag (_flags & ~PositionLocked);
922 send_change (LockChanged);
927 Region::set_sync_position (nframes_t absolute_pos)
931 file_pos = _start + (absolute_pos - _position);
933 if (file_pos != _sync_position) {
935 _sync_position = file_pos;
936 _flags = Flag (_flags|SyncMarked);
941 send_change (SyncOffsetChanged);
946 Region::clear_sync_position ()
948 if (_flags & SyncMarked) {
949 _flags = Flag (_flags & ~SyncMarked);
954 send_change (SyncOffsetChanged);
959 Region::sync_offset (int& dir) const
961 /* returns the sync point relative the first frame of the region */
963 if (_flags & SyncMarked) {
964 if (_sync_position > _start) {
966 return _sync_position - _start;
969 return _start - _sync_position;
978 Region::adjust_to_sync (nframes_t pos)
981 nframes_t offset = sync_offset (sync_dir);
983 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
992 if (max_frames - pos > offset) {
1001 Region::sync_position() const
1003 if (_flags & SyncMarked) {
1004 return _sync_position;
1013 boost::shared_ptr<Playlist> pl (playlist());
1015 pl->raise_region (shared_from_this ());
1022 boost::shared_ptr<Playlist> pl (playlist());
1024 pl->lower_region (shared_from_this ());
1030 Region::raise_to_top ()
1032 boost::shared_ptr<Playlist> pl (playlist());
1034 pl->raise_region_to_top (shared_from_this());
1039 Region::lower_to_bottom ()
1041 boost::shared_ptr<Playlist> pl (playlist());
1043 pl->lower_region_to_bottom (shared_from_this());
1048 Region::set_layer (layer_t l)
1053 send_change (LayerChanged);
1058 Region::state (bool full_state)
1060 XMLNode *node = new XMLNode ("Region");
1062 const char* fe = NULL;
1064 _id.print (buf, sizeof (buf));
1065 node->add_property ("id", buf);
1066 node->add_property ("name", _name);
1067 node->add_property ("type", _type.to_string());
1068 snprintf (buf, sizeof (buf), "%u", _start);
1069 node->add_property ("start", buf);
1070 snprintf (buf, sizeof (buf), "%u", _length);
1071 node->add_property ("length", buf);
1072 snprintf (buf, sizeof (buf), "%u", _position);
1073 node->add_property ("position", buf);
1074 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1075 node->add_property ("ancestral-start", buf);
1076 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1077 node->add_property ("ancestral-length", buf);
1078 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1079 node->add_property ("stretch", buf);
1080 snprintf (buf, sizeof (buf), "%.12g", _shift);
1081 node->add_property ("shift", buf);
1083 switch (_first_edit) {
1084 case EditChangesNothing:
1087 case EditChangesName:
1093 default: /* should be unreachable but makes g++ happy */
1098 node->add_property ("first_edit", fe);
1100 /* note: flags are stored by derived classes */
1102 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1103 node->add_property ("layer", buf);
1104 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1105 node->add_property ("sync-position", buf);
1107 if (_positional_lock_style != AudioTime) {
1108 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1111 node->add_property ("bbt-position", str.str());
1118 Region::get_state ()
1120 return state (true);
1124 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1126 const XMLNodeList& nlist = node.children();
1127 const XMLProperty *prop;
1130 /* this is responsible for setting those aspects of Region state
1131 that are mutable after construction.
1134 if ((prop = node.property ("name")) == 0) {
1135 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1139 _name = prop->value();
1141 if ((prop = node.property ("type")) == 0) {
1142 _type = DataType::AUDIO;
1144 _type = DataType(prop->value());
1147 if ((prop = node.property ("start")) != 0) {
1148 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1149 if (val != _start) {
1150 what_changed = Change (what_changed|StartChanged);
1157 if ((prop = node.property ("length")) != 0) {
1158 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1159 if (val != _length) {
1160 what_changed = Change (what_changed|LengthChanged);
1161 _last_length = _length;
1165 _last_length = _length;
1169 if ((prop = node.property ("position")) != 0) {
1170 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1171 if (val != _position) {
1172 what_changed = Change (what_changed|PositionChanged);
1173 _last_position = _position;
1177 _last_position = _position;
1181 if ((prop = node.property ("layer")) != 0) {
1183 x = (layer_t) atoi (prop->value().c_str());
1185 what_changed = Change (what_changed|LayerChanged);
1192 if ((prop = node.property ("sync-position")) != 0) {
1193 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1194 if (val != _sync_position) {
1195 what_changed = Change (what_changed|SyncOffsetChanged);
1196 _sync_position = val;
1199 _sync_position = _start;
1202 if ((prop = node.property ("positional-lock-style")) != 0) {
1203 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1205 if (_positional_lock_style == MusicTime) {
1206 if ((prop = node.property ("bbt-position")) == 0) {
1207 /* missing BBT info, revert to audio time locking */
1208 _positional_lock_style = AudioTime;
1210 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1213 &_bbt_time.ticks) != 3) {
1214 _positional_lock_style = AudioTime;
1220 _positional_lock_style = AudioTime;
1223 /* XXX FIRST EDIT !!! */
1225 /* these 3 properties never change as a result of any editing */
1227 if ((prop = node.property ("ancestral-start")) != 0) {
1228 _ancestral_start = atoi (prop->value());
1230 _ancestral_start = _start;
1233 if ((prop = node.property ("ancestral-length")) != 0) {
1234 _ancestral_length = atoi (prop->value());
1236 _ancestral_length = _length;
1239 if ((prop = node.property ("stretch")) != 0) {
1240 _stretch = atof (prop->value());
1245 if ((prop = node.property ("shift")) != 0) {
1246 _shift = atof (prop->value());
1251 /* note: derived classes set flags */
1258 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1264 if (child->name () == "extra") {
1265 _extra_xml = new XMLNode (*child);
1271 send_change (what_changed);
1278 Region::set_state (const XMLNode& node)
1280 const XMLProperty *prop;
1281 Change what_changed = Change (0);
1283 /* ID is not allowed to change, ever */
1285 if ((prop = node.property ("id")) == 0) {
1286 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1290 _id = prop->value();
1292 _first_edit = EditChangesNothing;
1294 set_live_state (node, what_changed, true);
1303 _last_length = _length;
1304 _last_position = _position;
1308 Region::thaw (const string& why)
1310 Change what_changed = Change (0);
1313 Glib::Mutex::Lock lm (_lock);
1315 if (_frozen && --_frozen > 0) {
1319 if (_pending_changed) {
1320 what_changed = _pending_changed;
1321 _pending_changed = Change (0);
1325 if (what_changed == Change (0)) {
1329 if (what_changed & LengthChanged) {
1330 if (what_changed & PositionChanged) {
1331 recompute_at_start ();
1333 recompute_at_end ();
1336 StateChanged (what_changed);
1340 Region::send_change (Change what_changed)
1343 Glib::Mutex::Lock lm (_lock);
1345 _pending_changed = Change (_pending_changed|what_changed);
1350 StateChanged (what_changed);
1354 Region::set_last_layer_op (uint64_t when)
1356 _last_layer_op = when;
1360 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1362 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1366 Region::equivalent (boost::shared_ptr<const Region> other) const
1368 return _start == other->_start &&
1369 _position == other->_position &&
1370 _length == other->_length;
1374 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1376 return _start == other->_start &&
1377 _length == other->_length;
1381 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1383 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1387 Region::source_deleted (boost::shared_ptr<Source>)
1394 Region::master_source_names ()
1396 SourceList::iterator i;
1398 vector<string> names;
1399 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1400 names.push_back((*i)->name());
1407 Region::set_master_sources (SourceList& srcs)
1409 _master_sources = srcs;
1413 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1418 SourceList::const_iterator i;
1419 SourceList::const_iterator io;
1421 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1422 if ((*i)->id() != (*io)->id()) {
1427 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1428 if ((*i)->id() != (*io)->id()) {
1437 Region::verify_length (nframes_t len)
1439 if (source() && (source()->destructive() || source()->length_mutable())) {
1443 nframes_t maxlen = 0;
1445 for (uint32_t n=0; n < _sources.size(); ++n) {
1446 maxlen = max (maxlen, _sources[n]->length() - _start);
1449 len = min (len, maxlen);
1455 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
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() - new_start);
1467 new_length = min (new_length, maxlen);
1473 Region::verify_start (nframes_t pos)
1475 if (source() && (source()->destructive() || source()->length_mutable())) {
1479 for (uint32_t n=0; n < _sources.size(); ++n) {
1480 if (pos > _sources[n]->length() - _length) {
1488 Region::verify_start_mutable (nframes_t& new_start)
1490 if (source() && (source()->destructive() || source()->length_mutable())) {
1494 for (uint32_t n=0; n < _sources.size(); ++n) {
1495 if (new_start > _sources[n]->length() - _length) {
1496 new_start = _sources[n]->length() - _length;
1502 boost::shared_ptr<Region>
1503 Region::get_parent() const
1505 boost::shared_ptr<Playlist> pl (playlist());
1508 boost::shared_ptr<Region> r;
1509 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1511 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1512 return boost::static_pointer_cast<Region> (r);
1516 return boost::shared_ptr<Region>();
1520 Region::apply (Filter& filter)
1522 return filter.run (shared_from_this());
1527 Region::invalidate_transients ()
1529 _valid_transients = false;
1530 _transients.clear ();