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;
189 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
190 if (unique_srcs.find (*i) == unique_srcs.end()) {
191 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
193 _master_sources.push_back (*i);
196 assert(_sources.size() > 0);
199 /** Pure copy constructor */
200 Region::Region (boost::shared_ptr<const Region> other)
201 : Automatable(other->session(), other->name())
202 , _type(other->data_type())
203 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
204 , _start(other->_start)
205 , _length(other->_length)
206 , _position(other->_position)
207 , _last_position(other->_last_position)
208 , _positional_lock_style(other->_positional_lock_style)
209 , _sync_position(other->_sync_position)
210 , _layer(other->_layer)
211 , _first_edit(EditChangesID)
213 , _ancestral_start (_start)
214 , _ancestral_length (_length)
217 , _valid_transients(false)
218 , _read_data_count(0)
219 , _pending_changed(Change(0))
220 , _last_layer_op(other->_last_layer_op)
222 other->_first_edit = EditChangesName;
224 if (other->_extra_xml) {
225 _extra_xml = new XMLNode (*other->_extra_xml);
230 set<boost::shared_ptr<Source> > unique_srcs;
232 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
233 _sources.push_back (*i);
234 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
235 unique_srcs.insert (*i);
238 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
239 _master_sources.push_back (*i);
240 if (unique_srcs.find (*i) == unique_srcs.end()) {
241 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
245 assert(_sources.size() > 0);
248 Region::Region (const SourceList& srcs, const XMLNode& node)
249 : Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
250 , _type(DataType::NIL) // to be loaded from XML
256 , _positional_lock_style(AudioTime)
257 , _sync_position(_start)
259 , _first_edit(EditChangesNothing)
262 , _read_data_count(0)
263 , _pending_changed(Change(0))
266 set<boost::shared_ptr<Source> > unique_srcs;
268 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
269 _sources.push_back (*i);
270 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
271 unique_srcs.insert (*i);
274 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
275 _master_sources.push_back (*i);
276 if (unique_srcs.find (*i) == unique_srcs.end()) {
277 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
281 if (set_state (node)) {
282 throw failed_constructor();
285 assert(_type != DataType::NIL);
286 assert(_sources.size() > 0);
289 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
290 : Automatable(src->session(), X_("error: XML did not reset this"))
291 , _type(DataType::NIL)
297 , _positional_lock_style(AudioTime)
298 , _sync_position(_start)
300 , _first_edit(EditChangesNothing)
303 , _read_data_count(0)
304 , _pending_changed(Change(0))
307 _sources.push_back (src);
309 if (set_state (node)) {
310 throw failed_constructor();
313 assert(_type != DataType::NIL);
314 assert(_sources.size() > 0);
319 boost::shared_ptr<Playlist> pl (playlist());
322 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
323 (*i)->remove_playlist (pl);
325 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
326 (*i)->remove_playlist (pl);
331 GoingAway (); /* EMIT SIGNAL */
335 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
337 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
339 boost::shared_ptr<Playlist> pl (wpl.lock());
341 if (old_playlist == pl) {
349 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
350 (*i)->remove_playlist (_playlist);
351 (*i)->add_playlist (pl);
353 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
354 (*i)->remove_playlist (_playlist);
355 (*i)->add_playlist (pl);
358 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
359 (*i)->add_playlist (pl);
361 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
362 (*i)->add_playlist (pl);
367 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
368 (*i)->remove_playlist (old_playlist);
370 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
371 (*i)->remove_playlist (old_playlist);
378 Region::set_name (const std::string& str)
381 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
382 assert(_name == str);
383 send_change (ARDOUR::NameChanged);
390 Region::set_length (nframes_t len, void *src)
392 //cerr << "Region::set_length() len = " << len << endl;
393 if (_flags & Locked) {
397 if (_length != len && len != 0) {
399 /* check that the current _position wouldn't make the new
403 if (max_frames - len < _position) {
407 if (!verify_length (len)) {
412 _last_length = _length;
415 _flags = Region::Flag (_flags & ~WholeFile);
419 invalidate_transients ();
425 send_change (LengthChanged);
430 Region::maybe_uncopy ()
435 Region::first_edit ()
437 boost::shared_ptr<Playlist> pl (playlist());
439 if (_first_edit != EditChangesNothing && pl) {
441 _name = pl->session().new_region_name (_name);
442 _first_edit = EditChangesNothing;
444 send_change (ARDOUR::NameChanged);
445 RegionFactory::CheckNewRegion (shared_from_this());
450 Region::at_natural_position () const
452 boost::shared_ptr<Playlist> pl (playlist());
458 boost::shared_ptr<Region> whole_file_region = get_parent();
460 if (whole_file_region) {
461 if (_position == whole_file_region->position() + _start) {
470 Region::move_to_natural_position (void *src)
472 boost::shared_ptr<Playlist> pl (playlist());
478 boost::shared_ptr<Region> whole_file_region = get_parent();
480 if (whole_file_region) {
481 set_position (whole_file_region->position() + _start, src);
486 Region::special_set_position (nframes_t pos)
488 /* this is used when creating a whole file region as
489 a way to store its "natural" or "captured" position.
492 _position = _position;
497 Region::set_position_lock_style (PositionLockStyle ps)
499 boost::shared_ptr<Playlist> pl (playlist());
505 _positional_lock_style = ps;
507 if (_positional_lock_style == MusicTime) {
508 pl->session().tempo_map().bbt_time (_position, _bbt_time);
514 Region::update_position_after_tempo_map_change ()
516 boost::shared_ptr<Playlist> pl (playlist());
518 if (!pl || _positional_lock_style != MusicTime) {
522 TempoMap& map (pl->session().tempo_map());
523 nframes_t pos = map.frame_time (_bbt_time);
524 set_position_internal (pos, false);
528 Region::set_position (nframes_t pos, void *src)
534 set_position_internal (pos, true);
538 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
540 if (_position != pos) {
541 _last_position = _position;
544 /* check that the new _position wouldn't make the current
545 length impossible - if so, change the length.
547 XXX is this the right thing to do?
550 if (max_frames - _length < _position) {
551 _last_length = _length;
552 _length = max_frames - _position;
555 if (allow_bbt_recompute) {
556 recompute_position_from_lock_style ();
559 invalidate_transients ();
562 /* do this even if the position is the same. this helps out
563 a GUI that has moved its representation already.
566 send_change (PositionChanged);
570 Region::set_position_on_top (nframes_t pos, void *src)
572 if (_flags & Locked) {
576 if (_position != pos) {
577 _last_position = _position;
581 boost::shared_ptr<Playlist> pl (playlist());
584 pl->raise_region_to_top (shared_from_this ());
587 /* do this even if the position is the same. this helps out
588 a GUI that has moved its representation already.
591 send_change (PositionChanged);
595 Region::recompute_position_from_lock_style ()
597 if (_positional_lock_style == MusicTime) {
598 boost::shared_ptr<Playlist> pl (playlist());
600 pl->session().tempo_map().bbt_time (_position, _bbt_time);
606 Region::nudge_position (nframes64_t n, void *src)
608 if (_flags & Locked) {
616 _last_position = _position;
619 if (_position > max_frames - n) {
620 _position = max_frames;
625 if (_position < (nframes_t) -n) {
632 send_change (PositionChanged);
636 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
638 _ancestral_length = l;
639 _ancestral_start = s;
645 Region::set_start (nframes_t pos, void *src)
647 if (_flags & (Locked|PositionLocked)) {
650 /* This just sets the start, nothing else. It effectively shifts
651 the contents of the Region within the overall extent of the Source,
652 without changing the Region's position or length
657 if (!verify_start (pos)) {
662 _flags = Region::Flag (_flags & ~WholeFile);
664 invalidate_transients ();
666 send_change (StartChanged);
671 Region::trim_start (nframes_t new_position, void *src)
673 if (_flags & (Locked|PositionLocked)) {
679 if (new_position > _position) {
680 start_shift = new_position - _position;
682 start_shift = -(_position - new_position);
685 if (start_shift > 0) {
687 if (_start > max_frames - start_shift) {
688 new_start = max_frames;
690 new_start = _start + start_shift;
693 if (!verify_start (new_start)) {
697 } else if (start_shift < 0) {
699 if (_start < (nframes_t) -start_shift) {
702 new_start = _start + start_shift;
708 if (new_start == _start) {
713 _flags = Region::Flag (_flags & ~WholeFile);
716 send_change (StartChanged);
720 Region::trim_front (nframes_t new_position, void *src)
722 if (_flags & Locked) {
726 nframes_t end = last_frame();
727 nframes_t source_zero;
729 if (_position > _start) {
730 source_zero = _position - _start;
732 source_zero = 0; // its actually negative, but this will work for us
735 if (new_position < end) { /* can't trim it zero or negative length */
739 /* can't trim it back passed where source position zero is located */
741 new_position = max (new_position, source_zero);
744 if (new_position > _position) {
745 newlen = _length - (new_position - _position);
747 newlen = _length + (_position - new_position);
750 trim_to_internal (new_position, newlen, src);
752 recompute_at_start ();
758 Region::trim_end (nframes_t new_endpoint, void *src)
760 if (_flags & Locked) {
764 if (new_endpoint > _position) {
765 trim_to_internal (_position, new_endpoint - _position, this);
773 Region::trim_to (nframes_t position, nframes_t length, void *src)
775 if (_flags & Locked) {
779 trim_to_internal (position, length, src);
782 recompute_at_start ();
788 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
793 if (_flags & Locked) {
797 if (position > _position) {
798 start_shift = position - _position;
800 start_shift = -(_position - position);
803 if (start_shift > 0) {
805 if (_start > max_frames - start_shift) {
806 new_start = max_frames;
808 new_start = _start + start_shift;
812 } else if (start_shift < 0) {
814 if (_start < (nframes_t) -start_shift) {
817 new_start = _start + start_shift;
823 if (!verify_start_and_length (new_start, length)) {
827 Change what_changed = Change (0);
829 if (_start != new_start) {
831 what_changed = Change (what_changed|StartChanged);
833 if (_length != length) {
835 _last_length = _length;
838 what_changed = Change (what_changed|LengthChanged);
840 if (_position != position) {
842 _last_position = _position;
844 _position = position;
845 what_changed = Change (what_changed|PositionChanged);
848 _flags = Region::Flag (_flags & ~WholeFile);
850 if (what_changed & (StartChanged|LengthChanged)) {
855 send_change (what_changed);
860 Region::set_hidden (bool yn)
862 if (hidden() != yn) {
865 _flags = Flag (_flags|Hidden);
867 _flags = Flag (_flags & ~Hidden);
870 send_change (HiddenChanged);
875 Region::set_muted (bool yn)
880 _flags = Flag (_flags|Muted);
882 _flags = Flag (_flags & ~Muted);
885 send_change (MuteChanged);
890 Region::set_opaque (bool yn)
892 if (opaque() != yn) {
894 _flags = Flag (_flags|Opaque);
896 _flags = Flag (_flags & ~Opaque);
898 send_change (OpacityChanged);
903 Region::set_locked (bool yn)
905 if (locked() != yn) {
907 _flags = Flag (_flags|Locked);
909 _flags = Flag (_flags & ~Locked);
911 send_change (LockChanged);
916 Region::set_position_locked (bool yn)
918 if (position_locked() != yn) {
920 _flags = Flag (_flags|PositionLocked);
922 _flags = Flag (_flags & ~PositionLocked);
924 send_change (LockChanged);
929 Region::set_sync_position (nframes_t absolute_pos)
933 file_pos = _start + (absolute_pos - _position);
935 if (file_pos != _sync_position) {
937 _sync_position = file_pos;
938 _flags = Flag (_flags|SyncMarked);
943 send_change (SyncOffsetChanged);
948 Region::clear_sync_position ()
950 if (_flags & SyncMarked) {
951 _flags = Flag (_flags & ~SyncMarked);
956 send_change (SyncOffsetChanged);
961 Region::sync_offset (int& dir) const
963 /* returns the sync point relative the first frame of the region */
965 if (_flags & SyncMarked) {
966 if (_sync_position > _start) {
968 return _sync_position - _start;
971 return _start - _sync_position;
980 Region::adjust_to_sync (nframes_t pos)
983 nframes_t offset = sync_offset (sync_dir);
985 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
994 if (max_frames - pos > offset) {
1003 Region::sync_position() const
1005 if (_flags & SyncMarked) {
1006 return _sync_position;
1015 boost::shared_ptr<Playlist> pl (playlist());
1017 pl->raise_region (shared_from_this ());
1024 boost::shared_ptr<Playlist> pl (playlist());
1026 pl->lower_region (shared_from_this ());
1032 Region::raise_to_top ()
1034 boost::shared_ptr<Playlist> pl (playlist());
1036 pl->raise_region_to_top (shared_from_this());
1041 Region::lower_to_bottom ()
1043 boost::shared_ptr<Playlist> pl (playlist());
1045 pl->lower_region_to_bottom (shared_from_this());
1050 Region::set_layer (layer_t l)
1055 send_change (LayerChanged);
1060 Region::state (bool full_state)
1062 XMLNode *node = new XMLNode ("Region");
1064 const char* fe = NULL;
1066 _id.print (buf, sizeof (buf));
1067 node->add_property ("id", buf);
1068 node->add_property ("name", _name);
1069 node->add_property ("type", _type.to_string());
1070 snprintf (buf, sizeof (buf), "%u", _start);
1071 node->add_property ("start", buf);
1072 snprintf (buf, sizeof (buf), "%u", _length);
1073 node->add_property ("length", buf);
1074 snprintf (buf, sizeof (buf), "%u", _position);
1075 node->add_property ("position", buf);
1076 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1077 node->add_property ("ancestral-start", buf);
1078 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1079 node->add_property ("ancestral-length", buf);
1080 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1081 node->add_property ("stretch", buf);
1082 snprintf (buf, sizeof (buf), "%.12g", _shift);
1083 node->add_property ("shift", buf);
1085 switch (_first_edit) {
1086 case EditChangesNothing:
1089 case EditChangesName:
1095 default: /* should be unreachable but makes g++ happy */
1100 node->add_property ("first_edit", fe);
1102 /* note: flags are stored by derived classes */
1104 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1105 node->add_property ("layer", buf);
1106 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1107 node->add_property ("sync-position", buf);
1109 if (_positional_lock_style != AudioTime) {
1110 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1113 node->add_property ("bbt-position", str.str());
1120 Region::get_state ()
1122 return state (true);
1126 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1128 const XMLNodeList& nlist = node.children();
1129 const XMLProperty *prop;
1132 /* this is responsible for setting those aspects of Region state
1133 that are mutable after construction.
1136 if ((prop = node.property ("name")) == 0) {
1137 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1141 _name = prop->value();
1143 if ((prop = node.property ("type")) == 0) {
1144 _type = DataType::AUDIO;
1146 _type = DataType(prop->value());
1149 if ((prop = node.property ("start")) != 0) {
1150 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1151 if (val != _start) {
1152 what_changed = Change (what_changed|StartChanged);
1159 if ((prop = node.property ("length")) != 0) {
1160 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1161 if (val != _length) {
1162 what_changed = Change (what_changed|LengthChanged);
1163 _last_length = _length;
1167 _last_length = _length;
1171 if ((prop = node.property ("position")) != 0) {
1172 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1173 if (val != _position) {
1174 what_changed = Change (what_changed|PositionChanged);
1175 _last_position = _position;
1179 _last_position = _position;
1183 if ((prop = node.property ("layer")) != 0) {
1185 x = (layer_t) atoi (prop->value().c_str());
1187 what_changed = Change (what_changed|LayerChanged);
1194 if ((prop = node.property ("sync-position")) != 0) {
1195 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1196 if (val != _sync_position) {
1197 what_changed = Change (what_changed|SyncOffsetChanged);
1198 _sync_position = val;
1201 _sync_position = _start;
1204 if ((prop = node.property ("positional-lock-style")) != 0) {
1205 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1207 if (_positional_lock_style == MusicTime) {
1208 if ((prop = node.property ("bbt-position")) == 0) {
1209 /* missing BBT info, revert to audio time locking */
1210 _positional_lock_style = AudioTime;
1212 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1215 &_bbt_time.ticks) != 3) {
1216 _positional_lock_style = AudioTime;
1222 _positional_lock_style = AudioTime;
1225 /* XXX FIRST EDIT !!! */
1227 /* these 3 properties never change as a result of any editing */
1229 if ((prop = node.property ("ancestral-start")) != 0) {
1230 _ancestral_start = atoi (prop->value());
1232 _ancestral_start = _start;
1235 if ((prop = node.property ("ancestral-length")) != 0) {
1236 _ancestral_length = atoi (prop->value());
1238 _ancestral_length = _length;
1241 if ((prop = node.property ("stretch")) != 0) {
1242 _stretch = atof (prop->value());
1247 if ((prop = node.property ("shift")) != 0) {
1248 _shift = atof (prop->value());
1253 /* note: derived classes set flags */
1260 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1266 if (child->name () == "extra") {
1267 _extra_xml = new XMLNode (*child);
1273 send_change (what_changed);
1280 Region::set_state (const XMLNode& node)
1282 const XMLProperty *prop;
1283 Change what_changed = Change (0);
1285 /* ID is not allowed to change, ever */
1287 if ((prop = node.property ("id")) == 0) {
1288 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1292 _id = prop->value();
1294 _first_edit = EditChangesNothing;
1296 set_live_state (node, what_changed, true);
1305 _last_length = _length;
1306 _last_position = _position;
1310 Region::thaw (const string& why)
1312 Change what_changed = Change (0);
1315 Glib::Mutex::Lock lm (_lock);
1317 if (_frozen && --_frozen > 0) {
1321 if (_pending_changed) {
1322 what_changed = _pending_changed;
1323 _pending_changed = Change (0);
1327 if (what_changed == Change (0)) {
1331 if (what_changed & LengthChanged) {
1332 if (what_changed & PositionChanged) {
1333 recompute_at_start ();
1335 recompute_at_end ();
1338 StateChanged (what_changed);
1342 Region::send_change (Change what_changed)
1345 Glib::Mutex::Lock lm (_lock);
1347 _pending_changed = Change (_pending_changed|what_changed);
1352 StateChanged (what_changed);
1356 Region::set_last_layer_op (uint64_t when)
1358 _last_layer_op = when;
1362 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1364 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1368 Region::equivalent (boost::shared_ptr<const Region> other) const
1370 return _start == other->_start &&
1371 _position == other->_position &&
1372 _length == other->_length;
1376 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1378 return _start == other->_start &&
1379 _length == other->_length;
1383 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1385 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1389 Region::source_deleted (boost::shared_ptr<Source>)
1396 Region::master_source_names ()
1398 SourceList::iterator i;
1400 vector<string> names;
1401 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1402 names.push_back((*i)->name());
1409 Region::set_master_sources (SourceList& srcs)
1411 _master_sources = srcs;
1415 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1420 SourceList::const_iterator i;
1421 SourceList::const_iterator io;
1423 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1424 if ((*i)->id() != (*io)->id()) {
1429 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1430 if ((*i)->id() != (*io)->id()) {
1439 Region::verify_length (nframes_t len)
1441 if (source() && (source()->destructive() || source()->length_mutable())) {
1445 nframes_t maxlen = 0;
1447 for (uint32_t n=0; n < _sources.size(); ++n) {
1448 maxlen = max (maxlen, _sources[n]->length() - _start);
1451 len = min (len, maxlen);
1457 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1459 if (source() && (source()->destructive() || source()->length_mutable())) {
1463 nframes_t maxlen = 0;
1465 for (uint32_t n=0; n < _sources.size(); ++n) {
1466 maxlen = max (maxlen, _sources[n]->length() - new_start);
1469 new_length = min (new_length, maxlen);
1475 Region::verify_start (nframes_t pos)
1477 if (source() && (source()->destructive() || source()->length_mutable())) {
1481 for (uint32_t n=0; n < _sources.size(); ++n) {
1482 if (pos > _sources[n]->length() - _length) {
1490 Region::verify_start_mutable (nframes_t& new_start)
1492 if (source() && (source()->destructive() || source()->length_mutable())) {
1496 for (uint32_t n=0; n < _sources.size(); ++n) {
1497 if (new_start > _sources[n]->length() - _length) {
1498 new_start = _sources[n]->length() - _length;
1504 boost::shared_ptr<Region>
1505 Region::get_parent() const
1507 boost::shared_ptr<Playlist> pl (playlist());
1510 boost::shared_ptr<Region> r;
1511 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1513 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1514 return boost::static_pointer_cast<Region> (r);
1518 return boost::shared_ptr<Region>();
1522 Region::apply (Filter& filter)
1524 return filter.run (shared_from_this());
1529 Region::invalidate_transients ()
1531 _valid_transients = false;
1532 _transients.clear ();