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)
72 , _pending_changed(Change (0))
75 /* no sources at this point */
78 /** Basic Region constructor (single source) */
79 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
80 : Automatable(src->session(), name)
87 , _positional_lock_style(AudioTime)
88 , _sync_position(_start)
90 , _first_edit(EditChangesNothing)
92 , _ancestral_start (start)
93 , _ancestral_length (length)
96 , _valid_transients(false)
98 , _pending_changed(Change (0))
101 _sources.push_back (src);
102 _master_sources.push_back (src);
104 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
106 assert(_sources.size() > 0);
107 _positional_lock_style = AudioTime;
110 /** Basic Region constructor (many sources) */
111 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
112 : Automatable(srcs.front()->session(), name)
119 , _positional_lock_style(AudioTime)
120 , _sync_position(_start)
122 , _first_edit(EditChangesNothing)
124 , _read_data_count(0)
125 , _pending_changed(Change (0))
129 set<boost::shared_ptr<Source> > unique_srcs;
131 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
132 _sources.push_back (*i);
133 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
134 unique_srcs.insert (*i);
137 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
138 _master_sources.push_back (*i);
139 if (unique_srcs.find (*i) == unique_srcs.end()) {
140 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
144 assert(_sources.size() > 0);
147 /** Create a new Region from part of an existing one */
148 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
149 : Automatable(other->session(), name)
150 , _type(other->data_type())
151 , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
152 , _start(other->_start + offset)
156 , _positional_lock_style(other->_positional_lock_style)
157 , _sync_position(_start)
159 , _first_edit(EditChangesNothing)
161 , _ancestral_start (other->_ancestral_start + offset)
162 , _ancestral_length (length)
165 , _valid_transients(false)
166 , _read_data_count(0)
167 , _pending_changed(Change (0))
170 if (other->_sync_position < offset)
171 _sync_position = other->_sync_position;
173 set<boost::shared_ptr<Source> > unique_srcs;
175 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
176 _sources.push_back (*i);
177 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
178 unique_srcs.insert (*i);
181 if (other->_sync_position < offset) {
182 _sync_position = other->_sync_position;
185 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
186 if (unique_srcs.find (*i) == unique_srcs.end()) {
187 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
189 _master_sources.push_back (*i);
192 assert(_sources.size() > 0);
195 /** Pure copy constructor */
196 Region::Region (boost::shared_ptr<const Region> other)
197 : Automatable(other->session(), other->name())
198 , _type(other->data_type())
199 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
200 , _start(other->_start)
201 , _length(other->_length)
202 , _position(other->_position)
203 , _last_position(other->_last_position)
204 , _positional_lock_style(other->_positional_lock_style)
205 , _sync_position(other->_sync_position)
206 , _layer(other->_layer)
207 , _first_edit(EditChangesID)
209 , _ancestral_start (_start)
210 , _ancestral_length (_length)
213 , _valid_transients(false)
214 , _read_data_count(0)
215 , _pending_changed(Change(0))
216 , _last_layer_op(other->_last_layer_op)
218 other->_first_edit = EditChangesName;
220 if (other->_extra_xml) {
221 _extra_xml = new XMLNode (*other->_extra_xml);
226 set<boost::shared_ptr<Source> > unique_srcs;
228 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
229 _sources.push_back (*i);
230 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
231 unique_srcs.insert (*i);
234 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
235 _master_sources.push_back (*i);
236 if (unique_srcs.find (*i) == unique_srcs.end()) {
237 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
241 assert(_sources.size() > 0);
244 Region::Region (const SourceList& srcs, const XMLNode& node)
245 : Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
246 , _type(DataType::NIL) // to be loaded from XML
252 , _positional_lock_style(AudioTime)
253 , _sync_position(_start)
255 , _first_edit(EditChangesNothing)
257 , _read_data_count(0)
258 , _pending_changed(Change(0))
261 set<boost::shared_ptr<Source> > unique_srcs;
263 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
264 _sources.push_back (*i);
265 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
266 unique_srcs.insert (*i);
269 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
270 _master_sources.push_back (*i);
271 if (unique_srcs.find (*i) == unique_srcs.end()) {
272 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
276 if (set_state (node)) {
277 throw failed_constructor();
280 assert(_type != DataType::NIL);
281 assert(_sources.size() > 0);
284 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
285 : Automatable(src->session(), X_("error: XML did not reset this"))
286 , _type(DataType::NIL)
292 , _positional_lock_style(AudioTime)
293 , _sync_position(_start)
295 , _first_edit(EditChangesNothing)
297 , _read_data_count(0)
298 , _pending_changed(Change(0))
301 _sources.push_back (src);
303 if (set_state (node)) {
304 throw failed_constructor();
307 assert(_type != DataType::NIL);
308 assert(_sources.size() > 0);
313 boost::shared_ptr<Playlist> pl (playlist());
316 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
317 (*i)->remove_playlist (pl);
322 GoingAway (); /* EMIT SIGNAL */
326 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
328 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
330 boost::shared_ptr<Playlist> pl (wpl.lock());
332 if (old_playlist == pl) {
340 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
341 (*i)->remove_playlist (_playlist);
342 (*i)->add_playlist (pl);
345 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
346 (*i)->add_playlist (pl);
351 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
352 (*i)->remove_playlist (old_playlist);
359 Region::set_name (const std::string& str)
362 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
363 assert(_name == str);
364 send_change (ARDOUR::NameChanged);
371 Region::set_length (nframes_t len, void *src)
373 if (_flags & Locked) {
377 if (_length != len && len != 0) {
379 /* check that the current _position wouldn't make the new
383 if (max_frames - len < _position) {
387 if (!verify_length (len)) {
392 _last_length = _length;
395 _flags = Region::Flag (_flags & ~WholeFile);
399 invalidate_transients ();
405 send_change (LengthChanged);
410 Region::maybe_uncopy ()
415 Region::first_edit ()
417 boost::shared_ptr<Playlist> pl (playlist());
419 if (_first_edit != EditChangesNothing && pl) {
421 _name = pl->session().new_region_name (_name);
422 _first_edit = EditChangesNothing;
424 send_change (ARDOUR::NameChanged);
425 RegionFactory::CheckNewRegion (shared_from_this());
430 Region::at_natural_position () const
432 boost::shared_ptr<Playlist> pl (playlist());
438 boost::shared_ptr<Region> whole_file_region = get_parent();
440 if (whole_file_region) {
441 if (_position == whole_file_region->position() + _start) {
450 Region::move_to_natural_position (void *src)
452 boost::shared_ptr<Playlist> pl (playlist());
458 boost::shared_ptr<Region> whole_file_region = get_parent();
460 if (whole_file_region) {
461 set_position (whole_file_region->position() + _start, src);
466 Region::special_set_position (nframes_t pos)
468 /* this is used when creating a whole file region as
469 a way to store its "natural" or "captured" position.
472 _position = _position;
477 Region::set_position_lock_style (PositionLockStyle ps)
479 boost::shared_ptr<Playlist> pl (playlist());
485 _positional_lock_style = ps;
487 if (_positional_lock_style == MusicTime) {
488 pl->session().tempo_map().bbt_time (_position, _bbt_time);
494 Region::update_position_after_tempo_map_change ()
496 boost::shared_ptr<Playlist> pl (playlist());
498 if (!pl || _positional_lock_style != MusicTime) {
502 TempoMap& map (pl->session().tempo_map());
503 nframes_t pos = map.frame_time (_bbt_time);
504 set_position_internal (pos, false);
508 Region::set_position (nframes_t pos, void *src)
514 set_position_internal (pos, true);
518 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
520 if (_position != pos) {
521 _last_position = _position;
524 /* check that the new _position wouldn't make the current
525 length impossible - if so, change the length.
527 XXX is this the right thing to do?
530 if (max_frames - _length < _position) {
531 _last_length = _length;
532 _length = max_frames - _position;
535 if (allow_bbt_recompute && _positional_lock_style == MusicTime) {
536 boost::shared_ptr<Playlist> pl (playlist());
538 pl->session().tempo_map().bbt_time (_position, _bbt_time);
542 invalidate_transients ();
545 /* do this even if the position is the same. this helps out
546 a GUI that has moved its representation already.
549 send_change (PositionChanged);
553 Region::set_position_on_top (nframes_t pos, void *src)
555 if (_flags & Locked) {
559 if (_position != pos) {
560 _last_position = _position;
564 boost::shared_ptr<Playlist> pl (playlist());
567 pl->raise_region_to_top (shared_from_this ());
570 /* do this even if the position is the same. this helps out
571 a GUI that has moved its representation already.
574 send_change (PositionChanged);
578 Region::nudge_position (nframes64_t n, void *src)
580 if (_flags & Locked) {
588 _last_position = _position;
591 if (_position > max_frames - n) {
592 _position = max_frames;
597 if (_position < (nframes_t) -n) {
604 send_change (PositionChanged);
608 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
610 _ancestral_length = l;
611 _ancestral_start = s;
617 Region::set_start (nframes_t pos, void *src)
619 if (_flags & (Locked|PositionLocked)) {
622 /* This just sets the start, nothing else. It effectively shifts
623 the contents of the Region within the overall extent of the Source,
624 without changing the Region's position or length
629 if (!verify_start (pos)) {
634 _flags = Region::Flag (_flags & ~WholeFile);
636 invalidate_transients ();
638 send_change (StartChanged);
643 Region::trim_start (nframes_t new_position, void *src)
645 if (_flags & (Locked|PositionLocked)) {
651 if (new_position > _position) {
652 start_shift = new_position - _position;
654 start_shift = -(_position - new_position);
657 if (start_shift > 0) {
659 if (_start > max_frames - start_shift) {
660 new_start = max_frames;
662 new_start = _start + start_shift;
665 if (!verify_start (new_start)) {
669 } else if (start_shift < 0) {
671 if (_start < (nframes_t) -start_shift) {
674 new_start = _start + start_shift;
680 if (new_start == _start) {
685 _flags = Region::Flag (_flags & ~WholeFile);
688 send_change (StartChanged);
692 Region::trim_front (nframes_t new_position, void *src)
694 if (_flags & Locked) {
698 nframes_t end = last_frame();
699 nframes_t source_zero;
701 if (_position > _start) {
702 source_zero = _position - _start;
704 source_zero = 0; // its actually negative, but this will work for us
707 if (new_position < end) { /* can't trim it zero or negative length */
711 /* can't trim it back passed where source position zero is located */
713 new_position = max (new_position, source_zero);
716 if (new_position > _position) {
717 newlen = _length - (new_position - _position);
719 newlen = _length + (_position - new_position);
722 trim_to_internal (new_position, newlen, src);
724 recompute_at_start ();
730 Region::trim_end (nframes_t new_endpoint, void *src)
732 if (_flags & Locked) {
736 if (new_endpoint > _position) {
737 trim_to_internal (_position, new_endpoint - _position, this);
745 Region::trim_to (nframes_t position, nframes_t length, void *src)
747 if (_flags & Locked) {
751 trim_to_internal (position, length, src);
754 recompute_at_start ();
760 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
765 if (_flags & Locked) {
769 if (position > _position) {
770 start_shift = position - _position;
772 start_shift = -(_position - position);
775 if (start_shift > 0) {
777 if (_start > max_frames - start_shift) {
778 new_start = max_frames;
780 new_start = _start + start_shift;
784 } else if (start_shift < 0) {
786 if (_start < (nframes_t) -start_shift) {
789 new_start = _start + start_shift;
795 if (!verify_start_and_length (new_start, length)) {
799 Change what_changed = Change (0);
801 if (_start != new_start) {
803 what_changed = Change (what_changed|StartChanged);
805 if (_length != length) {
807 _last_length = _length;
810 what_changed = Change (what_changed|LengthChanged);
812 if (_position != position) {
814 _last_position = _position;
816 _position = position;
817 what_changed = Change (what_changed|PositionChanged);
820 _flags = Region::Flag (_flags & ~WholeFile);
822 if (what_changed & (StartChanged|LengthChanged)) {
827 send_change (what_changed);
832 Region::set_hidden (bool yn)
834 if (hidden() != yn) {
837 _flags = Flag (_flags|Hidden);
839 _flags = Flag (_flags & ~Hidden);
842 send_change (HiddenChanged);
847 Region::set_muted (bool yn)
852 _flags = Flag (_flags|Muted);
854 _flags = Flag (_flags & ~Muted);
857 send_change (MuteChanged);
862 Region::set_opaque (bool yn)
864 if (opaque() != yn) {
866 _flags = Flag (_flags|Opaque);
868 _flags = Flag (_flags & ~Opaque);
870 send_change (OpacityChanged);
875 Region::set_locked (bool yn)
877 if (locked() != yn) {
879 _flags = Flag (_flags|Locked);
881 _flags = Flag (_flags & ~Locked);
883 send_change (LockChanged);
888 Region::set_position_locked (bool yn)
890 if (position_locked() != yn) {
892 _flags = Flag (_flags|PositionLocked);
894 _flags = Flag (_flags & ~PositionLocked);
896 send_change (LockChanged);
901 Region::set_sync_position (nframes_t absolute_pos)
905 file_pos = _start + (absolute_pos - _position);
907 if (file_pos != _sync_position) {
909 _sync_position = file_pos;
910 _flags = Flag (_flags|SyncMarked);
915 send_change (SyncOffsetChanged);
920 Region::clear_sync_position ()
922 if (_flags & SyncMarked) {
923 _flags = Flag (_flags & ~SyncMarked);
928 send_change (SyncOffsetChanged);
933 Region::sync_offset (int& dir) const
935 /* returns the sync point relative the first frame of the region */
937 if (_flags & SyncMarked) {
938 if (_sync_position > _start) {
940 return _sync_position - _start;
943 return _start - _sync_position;
952 Region::adjust_to_sync (nframes_t pos)
955 nframes_t offset = sync_offset (sync_dir);
957 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
966 if (max_frames - pos > offset) {
975 Region::sync_position() const
977 if (_flags & SyncMarked) {
978 return _sync_position;
987 boost::shared_ptr<Playlist> pl (playlist());
989 pl->raise_region (shared_from_this ());
996 boost::shared_ptr<Playlist> pl (playlist());
998 pl->lower_region (shared_from_this ());
1004 Region::raise_to_top ()
1006 boost::shared_ptr<Playlist> pl (playlist());
1008 pl->raise_region_to_top (shared_from_this());
1013 Region::lower_to_bottom ()
1015 boost::shared_ptr<Playlist> pl (playlist());
1017 pl->lower_region_to_bottom (shared_from_this());
1022 Region::set_layer (layer_t l)
1027 send_change (LayerChanged);
1032 Region::state (bool full_state)
1034 XMLNode *node = new XMLNode ("Region");
1036 const char* fe = NULL;
1038 _id.print (buf, sizeof (buf));
1039 node->add_property ("id", buf);
1040 node->add_property ("name", _name);
1041 node->add_property ("type", _type.to_string());
1042 snprintf (buf, sizeof (buf), "%u", _start);
1043 node->add_property ("start", buf);
1044 snprintf (buf, sizeof (buf), "%u", _length);
1045 node->add_property ("length", buf);
1046 snprintf (buf, sizeof (buf), "%u", _position);
1047 node->add_property ("position", buf);
1048 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1049 node->add_property ("ancestral-start", buf);
1050 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1051 node->add_property ("ancestral-length", buf);
1052 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1053 node->add_property ("stretch", buf);
1054 snprintf (buf, sizeof (buf), "%.12g", _shift);
1055 node->add_property ("shift", buf);
1057 switch (_first_edit) {
1058 case EditChangesNothing:
1061 case EditChangesName:
1067 default: /* should be unreachable but makes g++ happy */
1072 node->add_property ("first_edit", fe);
1074 /* note: flags are stored by derived classes */
1076 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1077 node->add_property ("layer", buf);
1078 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1079 node->add_property ("sync-position", buf);
1081 if (_positional_lock_style != AudioTime) {
1082 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1085 node->add_property ("bbt-position", str.str());
1092 Region::get_state ()
1094 return state (true);
1098 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1100 const XMLNodeList& nlist = node.children();
1101 const XMLProperty *prop;
1104 /* this is responsible for setting those aspects of Region state
1105 that are mutable after construction.
1108 if ((prop = node.property ("name")) == 0) {
1109 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1113 _name = prop->value();
1115 if ((prop = node.property ("type")) == 0) {
1116 _type = DataType::AUDIO;
1118 _type = DataType(prop->value());
1121 if ((prop = node.property ("start")) != 0) {
1122 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1123 if (val != _start) {
1124 what_changed = Change (what_changed|StartChanged);
1131 if ((prop = node.property ("length")) != 0) {
1132 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1133 if (val != _length) {
1134 what_changed = Change (what_changed|LengthChanged);
1135 _last_length = _length;
1139 _last_length = _length;
1143 if ((prop = node.property ("position")) != 0) {
1144 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1145 if (val != _position) {
1146 what_changed = Change (what_changed|PositionChanged);
1147 _last_position = _position;
1151 _last_position = _position;
1155 if ((prop = node.property ("layer")) != 0) {
1157 x = (layer_t) atoi (prop->value().c_str());
1159 what_changed = Change (what_changed|LayerChanged);
1166 if ((prop = node.property ("sync-position")) != 0) {
1167 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1168 if (val != _sync_position) {
1169 what_changed = Change (what_changed|SyncOffsetChanged);
1170 _sync_position = val;
1173 _sync_position = _start;
1176 if ((prop = node.property ("positional-lock-style")) != 0) {
1177 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1179 if (_positional_lock_style == MusicTime) {
1180 if ((prop = node.property ("bbt-position")) == 0) {
1181 /* missing BBT info, revert to audio time locking */
1182 _positional_lock_style = AudioTime;
1184 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1187 &_bbt_time.ticks) != 3) {
1188 _positional_lock_style = AudioTime;
1194 _positional_lock_style = AudioTime;
1197 /* XXX FIRST EDIT !!! */
1199 /* these 3 properties never change as a result of any editing */
1201 if ((prop = node.property ("ancestral-start")) != 0) {
1202 _ancestral_start = atoi (prop->value());
1204 _ancestral_start = _start;
1207 if ((prop = node.property ("ancestral-length")) != 0) {
1208 _ancestral_length = atoi (prop->value());
1210 _ancestral_length = _length;
1213 if ((prop = node.property ("stretch")) != 0) {
1214 _stretch = atof (prop->value());
1219 if ((prop = node.property ("shift")) != 0) {
1220 _shift = atof (prop->value());
1225 /* note: derived classes set flags */
1232 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1238 if (child->name () == "extra") {
1239 _extra_xml = new XMLNode (*child);
1245 send_change (what_changed);
1252 Region::set_state (const XMLNode& node)
1254 const XMLProperty *prop;
1255 Change what_changed = Change (0);
1257 /* ID is not allowed to change, ever */
1259 if ((prop = node.property ("id")) == 0) {
1260 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1264 _id = prop->value();
1266 _first_edit = EditChangesNothing;
1268 set_live_state (node, what_changed, true);
1277 _last_length = _length;
1278 _last_position = _position;
1282 Region::thaw (const string& why)
1284 Change what_changed = Change (0);
1287 Glib::Mutex::Lock lm (_lock);
1289 if (_frozen && --_frozen > 0) {
1293 if (_pending_changed) {
1294 what_changed = _pending_changed;
1295 _pending_changed = Change (0);
1299 if (what_changed == Change (0)) {
1303 if (what_changed & LengthChanged) {
1304 if (what_changed & PositionChanged) {
1305 recompute_at_start ();
1307 recompute_at_end ();
1310 StateChanged (what_changed);
1314 Region::send_change (Change what_changed)
1317 Glib::Mutex::Lock lm (_lock);
1319 _pending_changed = Change (_pending_changed|what_changed);
1324 StateChanged (what_changed);
1328 Region::set_last_layer_op (uint64_t when)
1330 _last_layer_op = when;
1334 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1336 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1340 Region::equivalent (boost::shared_ptr<const Region> other) const
1342 return _start == other->_start &&
1343 _position == other->_position &&
1344 _length == other->_length;
1348 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1350 return _start == other->_start &&
1351 _length == other->_length;
1355 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1357 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1361 Region::source_deleted (boost::shared_ptr<Source>)
1368 Region::master_source_names ()
1370 SourceList::iterator i;
1372 vector<string> names;
1373 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1374 names.push_back((*i)->name());
1381 Region::set_master_sources (SourceList& srcs)
1383 _master_sources = srcs;
1387 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1392 SourceList::const_iterator i;
1393 SourceList::const_iterator io;
1395 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1396 if ((*i)->id() != (*io)->id()) {
1401 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1402 if ((*i)->id() != (*io)->id()) {
1411 Region::verify_length (nframes_t len)
1413 if (source() && (source()->destructive() || source()->length_mutable())) {
1417 nframes_t maxlen = 0;
1419 for (uint32_t n=0; n < _sources.size(); ++n) {
1420 maxlen = max (maxlen, _sources[n]->length() - _start);
1423 len = min (len, maxlen);
1429 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1431 if (source() && (source()->destructive() || source()->length_mutable())) {
1435 nframes_t maxlen = 0;
1437 for (uint32_t n=0; n < _sources.size(); ++n) {
1438 maxlen = max (maxlen, _sources[n]->length() - new_start);
1441 new_length = min (new_length, maxlen);
1447 Region::verify_start (nframes_t pos)
1449 if (source() && (source()->destructive() || source()->length_mutable())) {
1453 for (uint32_t n=0; n < _sources.size(); ++n) {
1454 if (pos > _sources[n]->length() - _length) {
1462 Region::verify_start_mutable (nframes_t& new_start)
1464 if (source() && (source()->destructive() || source()->length_mutable())) {
1468 for (uint32_t n=0; n < _sources.size(); ++n) {
1469 if (new_start > _sources[n]->length() - _length) {
1470 new_start = _sources[n]->length() - _length;
1476 boost::shared_ptr<Region>
1477 Region::get_parent() const
1479 boost::shared_ptr<Playlist> pl (playlist());
1482 boost::shared_ptr<Region> r;
1483 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1485 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1486 return boost::static_pointer_cast<Region> (r);
1490 return boost::shared_ptr<Region>();
1494 Region::apply (Filter& filter)
1496 return filter.run (shared_from_this());
1501 Region::invalidate_transients ()
1503 _valid_transients = false;
1504 _transients.clear ();