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/debug.h"
35 #include "ardour/region.h"
36 #include "ardour/playlist.h"
37 #include "ardour/session.h"
38 #include "ardour/source.h"
39 #include "ardour/tempo.h"
40 #include "ardour/region_factory.h"
41 #include "ardour/filter.h"
42 #include "ardour/profile.h"
43 #include "ardour/utils.h"
48 using namespace ARDOUR;
51 Change Region::FadeChanged = ARDOUR::new_change ();
52 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
53 Change Region::MuteChanged = ARDOUR::new_change ();
54 Change Region::OpacityChanged = ARDOUR::new_change ();
55 Change Region::LockChanged = ARDOUR::new_change ();
56 Change Region::LayerChanged = ARDOUR::new_change ();
57 Change Region::HiddenChanged = ARDOUR::new_change ();
59 sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
61 /* derived-from-derived constructor (no sources in constructor) */
62 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
63 : SessionObject(s, name)
65 , _flags(Flag (flags|DoNotSendPropertyChanges))
70 , _positional_lock_style(AudioTime)
71 , _sync_position(_start)
73 , _first_edit(EditChangesNothing)
75 , _ancestral_start (0)
76 , _ancestral_length (0)
80 , _pending_changed(Change (0))
82 , _pending_explicit_relayer (false)
84 /* no sources at this point */
87 /** Basic Region constructor (single source) */
88 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
89 : SessionObject(src->session(), name)
91 , _flags(Flag (flags|DoNotSendPropertyChanges))
96 , _positional_lock_style(AudioTime)
97 , _sync_position(_start)
99 , _first_edit(EditChangesNothing)
101 , _ancestral_start (0)
102 , _ancestral_length (0)
105 , _valid_transients(false)
106 , _read_data_count(0)
107 , _pending_changed(Change (0))
109 , _pending_explicit_relayer (false)
111 _sources.push_back (src);
112 _master_sources.push_back (src);
114 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
116 assert(_sources.size() > 0);
117 _positional_lock_style = AudioTime;
120 /** Basic Region constructor (many sources) */
121 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
122 : SessionObject(srcs.front()->session(), name)
124 , _flags(Flag (flags|DoNotSendPropertyChanges))
129 , _positional_lock_style(AudioTime)
130 , _sync_position(_start)
132 , _first_edit(EditChangesNothing)
134 , _ancestral_start (0)
135 , _ancestral_length (0)
138 , _read_data_count(0)
139 , _pending_changed(Change (0))
141 , _pending_explicit_relayer (false)
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 : SessionObject(other->session(), name)
150 , _type (other->data_type())
151 , _pending_explicit_relayer (false)
154 _start = other->_start + offset;
155 copy_stuff (other, offset, length, name, layer, flags);
157 _flags = Flag (_flags | DoNotSendPropertyChanges);
159 /* if the other region had a distinct sync point
160 set, then continue to use it as best we can.
161 otherwise, reset sync point back to start.
164 if (other->flags() & SyncMarked) {
165 if (other->_sync_position < _start) {
166 _flags = Flag (_flags & ~SyncMarked);
167 _sync_position = _start;
169 _sync_position = other->_sync_position;
172 _flags = Flag (_flags & ~SyncMarked);
173 _sync_position = _start;
176 if (Profile->get_sae()) {
177 /* reset sync point to start if its ended up
178 outside region bounds.
181 if (_sync_position < _start || _sync_position >= _start + _length) {
182 _flags = Flag (_flags & ~SyncMarked);
183 _sync_position = _start;
188 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
189 : SessionObject(other->session(), name)
190 , _type (other->data_type())
191 , _pending_explicit_relayer (false)
193 /* create a new Region exactly like another but starting at 0 in its sources */
196 copy_stuff (other, 0, length, name, layer, flags);
198 _flags = Flag (_flags | DoNotSendPropertyChanges);
200 /* sync pos is relative to start of file. our start-in-file is now zero,
201 so set our sync position to whatever the the difference between
202 _start and _sync_pos was in the other region.
204 result is that our new sync pos points to the same point in our source(s)
205 as the sync in the other region did in its source(s).
207 since we start at zero in our source(s), it is not possible to use a sync point that
208 is before the start. reset it to _start if that was true in the other region.
211 if (other->flags() & SyncMarked) {
212 if (other->_start < other->_sync_position) {
213 /* sync pos was after the start point of the other region */
214 _sync_position = other->_sync_position - other->_start;
216 /* sync pos was before the start point of the other region. not possible here. */
217 _flags = Flag (_flags & ~SyncMarked);
218 _sync_position = _start;
221 _flags = Flag (_flags & ~SyncMarked);
222 _sync_position = _start;
225 if (Profile->get_sae()) {
226 /* reset sync point to start if its ended up
227 outside region bounds.
230 if (_sync_position < _start || _sync_position >= _start + _length) {
231 _flags = Flag (_flags & ~SyncMarked);
232 _sync_position = _start;
236 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
238 _positional_lock_style = other->_positional_lock_style;
239 _first_edit = other->_first_edit;
242 /** Pure copy constructor */
243 Region::Region (boost::shared_ptr<const Region> other)
244 : SessionObject(other->session(), other->name())
245 , _type(other->data_type())
246 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
247 , _start(other->_start)
248 , _length(other->_length)
249 , _position(other->_position)
250 , _last_position(other->_last_position)
251 , _positional_lock_style(other->_positional_lock_style)
252 , _sync_position(other->_sync_position)
253 , _layer(other->_layer)
254 , _first_edit(EditChangesID)
256 , _ancestral_start (other->_ancestral_start)
257 , _ancestral_length (other->_ancestral_length)
258 , _stretch (other->_stretch)
259 , _shift (other->_shift)
260 , _valid_transients(false)
261 , _read_data_count(0)
262 , _pending_changed(Change(0))
263 , _last_layer_op(other->_last_layer_op)
264 , _pending_explicit_relayer (false)
266 _flags = Flag (_flags | DoNotSendPropertyChanges);
268 other->_first_edit = EditChangesName;
270 if (other->_extra_xml) {
271 _extra_xml = new XMLNode (*other->_extra_xml);
276 use_sources (other->_sources);
277 assert(_sources.size() > 0);
280 Region::Region (const SourceList& srcs, const XMLNode& node)
281 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
282 , _type(DataType::NIL) // to be loaded from XML
283 , _flags(DoNotSendPropertyChanges)
288 , _positional_lock_style(AudioTime)
289 , _sync_position(_start)
291 , _first_edit(EditChangesNothing)
295 , _read_data_count(0)
296 , _pending_changed(Change(0))
298 , _pending_explicit_relayer (false)
302 if (set_state (node, Stateful::loading_state_version)) {
303 throw failed_constructor();
306 assert(_type != DataType::NIL);
307 assert(_sources.size() > 0);
310 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
311 : SessionObject(src->session(), X_("error: XML did not reset this"))
312 , _type(DataType::NIL)
313 , _flags(DoNotSendPropertyChanges)
318 , _positional_lock_style(AudioTime)
319 , _sync_position(_start)
321 , _first_edit(EditChangesNothing)
325 , _read_data_count(0)
326 , _pending_changed(Change(0))
328 , _pending_explicit_relayer (false)
330 _sources.push_back (src);
332 if (set_state (node, Stateful::loading_state_version)) {
333 throw failed_constructor();
336 assert(_type != DataType::NIL);
337 assert(_sources.size() > 0);
342 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
344 GoingAway (); /* EMIT SIGNAL */
348 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
351 _pending_changed = Change (0);
352 _read_data_count = 0;
353 _valid_transients = false;
356 _last_length = length;
357 _sync_position = other->_sync_position;
358 _ancestral_start = other->_ancestral_start;
359 _ancestral_length = other->_ancestral_length;
360 _stretch = other->_stretch;
361 _shift = other->_shift;
366 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
367 _first_edit = EditChangesNothing;
369 _positional_lock_style = AudioTime;
371 use_sources (other->_sources);
375 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
377 _playlist = wpl.lock();
381 Region::set_name (const std::string& str)
384 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
385 assert(_name == str);
386 send_change (ARDOUR::NameChanged);
393 Region::set_length (nframes_t len, void */*src*/)
395 //cerr << "Region::set_length() len = " << len << endl;
396 if (_flags & Locked) {
400 if (_length != len && len != 0) {
402 /* check that the current _position wouldn't make the new
406 if (max_frames - len < _position) {
410 if (!verify_length (len)) {
415 _last_length = _length;
418 _flags = Region::Flag (_flags & ~WholeFile);
422 invalidate_transients ();
428 send_change (LengthChanged);
433 Region::maybe_uncopy ()
438 Region::first_edit ()
440 boost::shared_ptr<Playlist> pl (playlist());
442 if (_first_edit != EditChangesNothing && pl) {
444 _name = _session.new_region_name (_name);
445 _first_edit = EditChangesNothing;
447 send_change (ARDOUR::NameChanged);
448 RegionFactory::CheckNewRegion (shared_from_this());
453 Region::at_natural_position () const
455 boost::shared_ptr<Playlist> pl (playlist());
461 boost::shared_ptr<Region> whole_file_region = get_parent();
463 if (whole_file_region) {
464 if (_position == whole_file_region->position() + _start) {
473 Region::move_to_natural_position (void *src)
475 boost::shared_ptr<Playlist> pl (playlist());
481 boost::shared_ptr<Region> whole_file_region = get_parent();
483 if (whole_file_region) {
484 set_position (whole_file_region->position() + _start, src);
489 Region::special_set_position (nframes_t pos)
491 /* this is used when creating a whole file region as
492 a way to store its "natural" or "captured" position.
495 _position = _position;
500 Region::set_position_lock_style (PositionLockStyle ps)
502 boost::shared_ptr<Playlist> pl (playlist());
508 _positional_lock_style = ps;
510 if (_positional_lock_style == MusicTime) {
511 _session.tempo_map().bbt_time (_position, _bbt_time);
517 Region::update_position_after_tempo_map_change ()
519 boost::shared_ptr<Playlist> pl (playlist());
521 if (!pl || _positional_lock_style != MusicTime) {
525 TempoMap& map (_session.tempo_map());
526 nframes_t pos = map.frame_time (_bbt_time);
527 set_position_internal (pos, false);
531 Region::set_position (nframes_t pos, void* /*src*/)
537 set_position_internal (pos, true);
541 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
543 if (_position != pos) {
544 _last_position = _position;
547 /* check that the new _position wouldn't make the current
548 length impossible - if so, change the length.
550 XXX is this the right thing to do?
553 if (max_frames - _length < _position) {
554 _last_length = _length;
555 _length = max_frames - _position;
558 if (allow_bbt_recompute) {
559 recompute_position_from_lock_style ();
562 invalidate_transients ();
565 /* do this even if the position is the same. this helps out
566 a GUI that has moved its representation already.
569 send_change (PositionChanged);
573 Region::set_position_on_top (nframes_t pos, void* /*src*/)
575 if (_flags & Locked) {
579 if (_position != pos) {
580 _last_position = _position;
584 boost::shared_ptr<Playlist> pl (playlist());
587 pl->raise_region_to_top (shared_from_this ());
590 /* do this even if the position is the same. this helps out
591 a GUI that has moved its representation already.
594 send_change (PositionChanged);
598 Region::recompute_position_from_lock_style ()
600 if (_positional_lock_style == MusicTime) {
601 _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 ();
757 /** @param new_endpoint New region end point, such that, for example,
758 * a region at 0 of length 10 has an endpoint of 9.
762 Region::trim_end (nframes_t new_endpoint, void */*src*/)
764 if (_flags & Locked) {
768 if (new_endpoint > _position) {
769 trim_to_internal (_position, new_endpoint - _position + 1, this);
777 Region::trim_to (nframes_t position, nframes_t length, void *src)
779 if (_flags & Locked) {
783 trim_to_internal (position, length, src);
786 recompute_at_start ();
792 Region::trim_to_internal (nframes_t position, nframes_t length, void */*src*/)
797 if (_flags & Locked) {
801 if (position > _position) {
802 start_shift = position - _position;
804 start_shift = -(_position - position);
807 if (start_shift > 0) {
809 if (_start > max_frames - start_shift) {
810 new_start = max_frames;
812 new_start = _start + start_shift;
816 } else if (start_shift < 0) {
818 if (_start < (nframes_t) -start_shift) {
821 new_start = _start + start_shift;
827 if (!verify_start_and_length (new_start, length)) {
831 Change what_changed = Change (0);
833 if (_start != new_start) {
835 what_changed = Change (what_changed|StartChanged);
837 if (_length != length) {
839 _last_length = _length;
842 what_changed = Change (what_changed|LengthChanged);
844 if (_position != position) {
846 _last_position = _position;
848 _position = position;
849 what_changed = Change (what_changed|PositionChanged);
852 _flags = Region::Flag (_flags & ~WholeFile);
854 if (what_changed & (StartChanged|LengthChanged)) {
859 send_change (what_changed);
864 Region::set_hidden (bool yn)
866 if (hidden() != yn) {
869 _flags = Flag (_flags|Hidden);
871 _flags = Flag (_flags & ~Hidden);
874 send_change (HiddenChanged);
879 Region::set_muted (bool yn)
884 _flags = Flag (_flags|Muted);
886 _flags = Flag (_flags & ~Muted);
889 send_change (MuteChanged);
894 Region::set_opaque (bool yn)
896 if (opaque() != yn) {
898 _flags = Flag (_flags|Opaque);
900 _flags = Flag (_flags & ~Opaque);
902 send_change (OpacityChanged);
907 Region::set_locked (bool yn)
909 if (locked() != yn) {
911 _flags = Flag (_flags|Locked);
913 _flags = Flag (_flags & ~Locked);
915 send_change (LockChanged);
920 Region::set_position_locked (bool yn)
922 if (position_locked() != yn) {
924 _flags = Flag (_flags|PositionLocked);
926 _flags = Flag (_flags & ~PositionLocked);
928 send_change (LockChanged);
933 Region::set_sync_position (nframes_t absolute_pos)
935 nframes_t const file_pos = _start + (absolute_pos - _position);
937 if (file_pos != _sync_position) {
939 _sync_position = file_pos;
940 _flags = Flag (_flags|SyncMarked);
945 send_change (SyncOffsetChanged);
950 Region::clear_sync_position ()
952 if (_flags & SyncMarked) {
953 _flags = Flag (_flags & ~SyncMarked);
958 send_change (SyncOffsetChanged);
963 Region::sync_offset (int& dir) const
965 /* returns the sync point relative the first frame of the region */
967 if (_flags & SyncMarked) {
968 if (_sync_position > _start) {
970 return _sync_position - _start;
973 return _start - _sync_position;
982 Region::adjust_to_sync (nframes_t pos) const
985 nframes_t offset = sync_offset (sync_dir);
987 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
996 if (max_frames - pos > offset) {
1005 Region::sync_position() const
1007 if (_flags & SyncMarked) {
1008 return _sync_position;
1017 boost::shared_ptr<Playlist> pl (playlist());
1019 pl->raise_region (shared_from_this ());
1026 boost::shared_ptr<Playlist> pl (playlist());
1028 pl->lower_region (shared_from_this ());
1034 Region::raise_to_top ()
1036 boost::shared_ptr<Playlist> pl (playlist());
1038 pl->raise_region_to_top (shared_from_this());
1043 Region::lower_to_bottom ()
1045 boost::shared_ptr<Playlist> pl (playlist());
1047 pl->lower_region_to_bottom (shared_from_this());
1052 Region::set_layer (layer_t l)
1057 send_change (LayerChanged);
1062 Region::state (bool /*full_state*/)
1064 XMLNode *node = new XMLNode ("Region");
1066 const char* fe = NULL;
1068 _id.print (buf, sizeof (buf));
1069 node->add_property ("id", buf);
1070 node->add_property ("name", _name);
1071 node->add_property ("type", _type.to_string());
1072 snprintf (buf, sizeof (buf), "%u", _start);
1073 node->add_property ("start", buf);
1074 snprintf (buf, sizeof (buf), "%u", _length);
1075 node->add_property ("length", buf);
1076 snprintf (buf, sizeof (buf), "%u", _position);
1077 node->add_property ("position", buf);
1078 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1079 node->add_property ("ancestral-start", buf);
1080 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1081 node->add_property ("ancestral-length", buf);
1082 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1083 node->add_property ("stretch", buf);
1084 snprintf (buf, sizeof (buf), "%.12g", _shift);
1085 node->add_property ("shift", buf);
1087 switch (_first_edit) {
1088 case EditChangesNothing:
1091 case EditChangesName:
1097 default: /* should be unreachable but makes g++ happy */
1102 node->add_property ("first-edit", fe);
1104 /* note: flags are stored by derived classes */
1106 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1107 node->add_property ("layer", buf);
1108 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1109 node->add_property ("sync-position", buf);
1111 if (_positional_lock_style != AudioTime) {
1112 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1115 node->add_property ("bbt-position", str.str());
1122 Region::get_state ()
1124 return state (true);
1128 Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
1130 const XMLNodeList& nlist = node.children();
1131 const XMLProperty *prop;
1134 /* this is responsible for setting those aspects of Region state
1135 that are mutable after construction.
1138 if ((prop = node.property ("name")) == 0) {
1139 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1143 _name = prop->value();
1145 if ((prop = node.property ("type")) == 0) {
1146 _type = DataType::AUDIO;
1148 _type = DataType(prop->value());
1151 if ((prop = node.property ("start")) != 0) {
1152 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1153 if (val != _start) {
1154 what_changed = Change (what_changed|StartChanged);
1161 if ((prop = node.property ("length")) != 0) {
1162 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1163 if (val != _length) {
1164 what_changed = Change (what_changed|LengthChanged);
1165 _last_length = _length;
1169 _last_length = _length;
1173 if ((prop = node.property ("position")) != 0) {
1174 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1175 if (val != _position) {
1176 what_changed = Change (what_changed|PositionChanged);
1177 _last_position = _position;
1181 _last_position = _position;
1185 if ((prop = node.property ("layer")) != 0) {
1187 x = (layer_t) atoi (prop->value().c_str());
1189 what_changed = Change (what_changed|LayerChanged);
1196 if ((prop = node.property ("sync-position")) != 0) {
1197 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1198 if (val != _sync_position) {
1199 what_changed = Change (what_changed|SyncOffsetChanged);
1200 _sync_position = val;
1203 _sync_position = _start;
1206 if ((prop = node.property ("positional-lock-style")) != 0) {
1207 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1209 if (_positional_lock_style == MusicTime) {
1210 if ((prop = node.property ("bbt-position")) == 0) {
1211 /* missing BBT info, revert to audio time locking */
1212 _positional_lock_style = AudioTime;
1214 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1217 &_bbt_time.ticks) != 3) {
1218 _positional_lock_style = AudioTime;
1224 _positional_lock_style = AudioTime;
1227 /* XXX FIRST EDIT !!! */
1229 /* these 3 properties never change as a result of any editing */
1231 if ((prop = node.property ("ancestral-start")) != 0) {
1232 _ancestral_start = strtoll (prop->value().c_str(), 0, 10);
1234 _ancestral_start = _start;
1237 if ((prop = node.property ("ancestral-length")) != 0) {
1238 _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
1240 _ancestral_length = _length;
1243 if ((prop = node.property ("stretch")) != 0) {
1244 _stretch = atof (prop->value());
1246 /* fix problem with old sessions corrupted by an impossible
1249 if (_stretch == 0.0) {
1256 if ((prop = node.property ("shift")) != 0) {
1257 _shift = atof (prop->value());
1259 /* fix problem with old sessions corrupted by an impossible
1262 if (_shift == 0.0) {
1270 /* note: derived classes set flags */
1275 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1281 if (child->name () == "Extra") {
1282 _extra_xml = new XMLNode (*child);
1288 send_change (what_changed);
1295 Region::set_state (const XMLNode& node, int version)
1297 const XMLProperty *prop;
1298 Change what_changed = Change (0);
1300 /* ID is not allowed to change, ever */
1302 if ((prop = node.property ("id")) == 0) {
1303 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1307 _id = prop->value();
1309 _first_edit = EditChangesNothing;
1311 set_live_state (node, version, what_changed, true);
1320 _last_length = _length;
1321 _last_position = _position;
1325 Region::thaw (const string& /*why*/)
1327 Change what_changed = Change (0);
1330 Glib::Mutex::Lock lm (_lock);
1332 if (_frozen && --_frozen > 0) {
1336 if (_pending_changed) {
1337 what_changed = _pending_changed;
1338 _pending_changed = Change (0);
1342 if (what_changed == Change (0)) {
1346 if (what_changed & LengthChanged) {
1347 if (what_changed & PositionChanged) {
1348 recompute_at_start ();
1350 recompute_at_end ();
1353 StateChanged (what_changed);
1357 Region::send_change (Change what_changed)
1360 Glib::Mutex::Lock lm (_lock);
1362 _pending_changed = Change (_pending_changed|what_changed);
1367 StateChanged (what_changed);
1369 if (!(_flags & DoNotSendPropertyChanges)) {
1371 /* Try and send a shared_pointer unless this is part of the constructor.
1376 boost::shared_ptr<Region> rptr = shared_from_this();
1377 RegionPropertyChanged (rptr);
1379 /* no shared_ptr available, relax; */
1386 Region::set_last_layer_op (uint64_t when)
1388 _last_layer_op = when;
1392 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1394 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1398 Region::equivalent (boost::shared_ptr<const Region> other) const
1400 return _start == other->_start &&
1401 _position == other->_position &&
1402 _length == other->_length;
1406 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1408 return _start == other->_start &&
1409 _length == other->_length;
1413 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1415 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1419 Region::source_deleted (boost::shared_ptr<Source>)
1426 Region::master_source_names ()
1428 SourceList::iterator i;
1430 vector<string> names;
1431 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1432 names.push_back((*i)->name());
1439 Region::set_master_sources (const SourceList& srcs)
1441 _master_sources = srcs;
1442 assert (_sources.size() == _master_sources.size());
1446 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1451 SourceList::const_iterator i;
1452 SourceList::const_iterator io;
1454 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1455 if ((*i)->id() != (*io)->id()) {
1460 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1461 if ((*i)->id() != (*io)->id()) {
1470 Region::uses_source (boost::shared_ptr<const Source> source) const
1472 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1481 Region::source_length(uint32_t n) const
1483 return _sources[n]->length(_position - _start);
1487 Region::verify_length (nframes_t len)
1489 if (source() && (source()->destructive() || source()->length_mutable())) {
1493 nframes_t maxlen = 0;
1495 for (uint32_t n=0; n < _sources.size(); ++n) {
1496 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1499 len = min (len, maxlen);
1505 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1507 if (source() && (source()->destructive() || source()->length_mutable())) {
1511 nframes_t maxlen = 0;
1513 for (uint32_t n=0; n < _sources.size(); ++n) {
1514 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1517 new_length = min (new_length, maxlen);
1523 Region::verify_start (nframes_t pos)
1525 if (source() && (source()->destructive() || source()->length_mutable())) {
1529 for (uint32_t n=0; n < _sources.size(); ++n) {
1530 if (pos > source_length(n) - _length) {
1538 Region::verify_start_mutable (nframes_t& new_start)
1540 if (source() && (source()->destructive() || source()->length_mutable())) {
1544 for (uint32_t n=0; n < _sources.size(); ++n) {
1545 if (new_start > source_length(n) - _length) {
1546 new_start = source_length(n) - _length;
1552 boost::shared_ptr<Region>
1553 Region::get_parent() const
1555 boost::shared_ptr<Playlist> pl (playlist());
1558 boost::shared_ptr<Region> r;
1559 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1561 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1562 return boost::static_pointer_cast<Region> (r);
1566 return boost::shared_ptr<Region>();
1570 Region::apply (Filter& filter)
1572 return filter.run (shared_from_this());
1577 Region::invalidate_transients ()
1579 _valid_transients = false;
1580 _transients.clear ();
1585 Region::use_sources (SourceList const & s)
1587 set<boost::shared_ptr<Source> > unique_srcs;
1589 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1590 _sources.push_back (*i);
1591 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));
1592 unique_srcs.insert (*i);
1595 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1596 _master_sources.push_back (*i);
1597 if (unique_srcs.find (*i) == unique_srcs.end()) {
1598 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));