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.
27 #include <glibmm/thread.h>
28 #include "pbd/xml++.h"
29 #include "pbd/stacktrace.h"
30 #include "pbd/enumwriter.h"
32 #include "ardour/debug.h"
33 #include "ardour/region.h"
34 #include "ardour/playlist.h"
35 #include "ardour/session.h"
36 #include "ardour/source.h"
37 #include "ardour/tempo.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/filter.h"
40 #include "ardour/profile.h"
41 #include "ardour/utils.h"
46 using namespace ARDOUR;
49 Change Region::FadeChanged = ARDOUR::new_change ();
50 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
51 Change Region::MuteChanged = ARDOUR::new_change ();
52 Change Region::OpacityChanged = ARDOUR::new_change ();
53 Change Region::LockChanged = ARDOUR::new_change ();
54 Change Region::LayerChanged = ARDOUR::new_change ();
55 Change Region::HiddenChanged = ARDOUR::new_change ();
57 boost::signals2::signal<void(boost::shared_ptr<ARDOUR::Region>)> Region::RegionPropertyChanged;
59 /* derived-from-derived constructor (no sources in constructor) */
60 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
61 : SessionObject(s, name)
63 , _flags(Flag (flags|DoNotSendPropertyChanges))
68 , _positional_lock_style(AudioTime)
69 , _sync_position(_start)
71 , _first_edit(EditChangesNothing)
73 , _ancestral_start (0)
74 , _ancestral_length (0)
78 , _pending_changed(Change (0))
80 , _pending_explicit_relayer (false)
82 /* no sources at this point */
85 /** Basic Region constructor (single source) */
86 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
87 : SessionObject(src->session(), name)
89 , _flags(Flag (flags|DoNotSendPropertyChanges))
94 , _positional_lock_style(AudioTime)
95 , _sync_position(_start)
97 , _first_edit(EditChangesNothing)
99 , _ancestral_start (0)
100 , _ancestral_length (0)
103 , _valid_transients(false)
104 , _read_data_count(0)
105 , _pending_changed(Change (0))
107 , _pending_explicit_relayer (false)
109 _sources.push_back (src);
110 _master_sources.push_back (src);
112 scoped_connect (src->GoingAway, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
114 assert(_sources.size() > 0);
115 _positional_lock_style = AudioTime;
118 /** Basic Region constructor (many sources) */
119 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
120 : SessionObject(srcs.front()->session(), name)
122 , _flags(Flag (flags|DoNotSendPropertyChanges))
127 , _positional_lock_style(AudioTime)
128 , _sync_position(_start)
130 , _first_edit(EditChangesNothing)
132 , _ancestral_start (0)
133 , _ancestral_length (0)
136 , _read_data_count(0)
137 , _pending_changed(Change (0))
139 , _pending_explicit_relayer (false)
142 assert(_sources.size() > 0);
145 /** Create a new Region from part of an existing one */
146 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
147 : SessionObject(other->session(), name)
148 , _type (other->data_type())
149 , _pending_explicit_relayer (false)
152 _start = other->_start + offset;
153 copy_stuff (other, offset, length, name, layer, flags);
155 _flags = Flag (_flags | DoNotSendPropertyChanges);
157 /* if the other region had a distinct sync point
158 set, then continue to use it as best we can.
159 otherwise, reset sync point back to start.
162 if (other->flags() & SyncMarked) {
163 if (other->_sync_position < _start) {
164 _flags = Flag (_flags & ~SyncMarked);
165 _sync_position = _start;
167 _sync_position = other->_sync_position;
170 _flags = Flag (_flags & ~SyncMarked);
171 _sync_position = _start;
174 if (Profile->get_sae()) {
175 /* reset sync point to start if its ended up
176 outside region bounds.
179 if (_sync_position < _start || _sync_position >= _start + _length) {
180 _flags = Flag (_flags & ~SyncMarked);
181 _sync_position = _start;
186 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
187 : SessionObject(other->session(), name)
188 , _type (other->data_type())
189 , _pending_explicit_relayer (false)
191 /* create a new Region exactly like another but starting at 0 in its sources */
194 copy_stuff (other, 0, length, name, layer, flags);
196 _flags = Flag (_flags | DoNotSendPropertyChanges);
198 /* sync pos is relative to start of file. our start-in-file is now zero,
199 so set our sync position to whatever the the difference between
200 _start and _sync_pos was in the other region.
202 result is that our new sync pos points to the same point in our source(s)
203 as the sync in the other region did in its source(s).
205 since we start at zero in our source(s), it is not possible to use a sync point that
206 is before the start. reset it to _start if that was true in the other region.
209 if (other->flags() & SyncMarked) {
210 if (other->_start < other->_sync_position) {
211 /* sync pos was after the start point of the other region */
212 _sync_position = other->_sync_position - other->_start;
214 /* sync pos was before the start point of the other region. not possible here. */
215 _flags = Flag (_flags & ~SyncMarked);
216 _sync_position = _start;
219 _flags = Flag (_flags & ~SyncMarked);
220 _sync_position = _start;
223 if (Profile->get_sae()) {
224 /* reset sync point to start if its ended up
225 outside region bounds.
228 if (_sync_position < _start || _sync_position >= _start + _length) {
229 _flags = Flag (_flags & ~SyncMarked);
230 _sync_position = _start;
234 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
236 _positional_lock_style = other->_positional_lock_style;
237 _first_edit = other->_first_edit;
240 /** Pure copy constructor */
241 Region::Region (boost::shared_ptr<const Region> other)
242 : SessionObject(other->session(), other->name())
243 , _type(other->data_type())
244 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
245 , _start(other->_start)
246 , _length(other->_length)
247 , _position(other->_position)
248 , _last_position(other->_last_position)
249 , _positional_lock_style(other->_positional_lock_style)
250 , _sync_position(other->_sync_position)
251 , _layer(other->_layer)
252 , _first_edit(EditChangesID)
254 , _ancestral_start (other->_ancestral_start)
255 , _ancestral_length (other->_ancestral_length)
256 , _stretch (other->_stretch)
257 , _shift (other->_shift)
258 , _valid_transients(false)
259 , _read_data_count(0)
260 , _pending_changed(Change(0))
261 , _last_layer_op(other->_last_layer_op)
262 , _pending_explicit_relayer (false)
264 _flags = Flag (_flags | DoNotSendPropertyChanges);
266 other->_first_edit = EditChangesName;
268 if (other->_extra_xml) {
269 _extra_xml = new XMLNode (*other->_extra_xml);
274 use_sources (other->_sources);
275 assert(_sources.size() > 0);
278 Region::Region (const SourceList& srcs, const XMLNode& node)
279 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
280 , _type(DataType::NIL) // to be loaded from XML
281 , _flags(DoNotSendPropertyChanges)
286 , _positional_lock_style(AudioTime)
287 , _sync_position(_start)
289 , _first_edit(EditChangesNothing)
293 , _read_data_count(0)
294 , _pending_changed(Change(0))
296 , _pending_explicit_relayer (false)
300 if (set_state (node, Stateful::loading_state_version)) {
301 throw failed_constructor();
304 assert(_type != DataType::NIL);
305 assert(_sources.size() > 0);
308 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
309 : SessionObject(src->session(), X_("error: XML did not reset this"))
310 , _type(DataType::NIL)
311 , _flags(DoNotSendPropertyChanges)
316 , _positional_lock_style(AudioTime)
317 , _sync_position(_start)
319 , _first_edit(EditChangesNothing)
323 , _read_data_count(0)
324 , _pending_changed(Change(0))
326 , _pending_explicit_relayer (false)
328 _sources.push_back (src);
330 if (set_state (node, Stateful::loading_state_version)) {
331 throw failed_constructor();
334 assert(_type != DataType::NIL);
335 assert(_sources.size() > 0);
340 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
345 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
348 _pending_changed = Change (0);
349 _read_data_count = 0;
350 _valid_transients = false;
353 _last_length = length;
354 _sync_position = other->_sync_position;
355 _ancestral_start = other->_ancestral_start;
356 _ancestral_length = other->_ancestral_length;
357 _stretch = other->_stretch;
358 _shift = other->_shift;
363 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
364 _first_edit = EditChangesNothing;
366 _positional_lock_style = AudioTime;
368 use_sources (other->_sources);
372 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
374 _playlist = wpl.lock();
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 = _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 _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 (_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 _session.tempo_map().bbt_time (_position, _bbt_time);
603 Region::nudge_position (nframes64_t n, void* /*src*/)
605 if (_flags & Locked) {
613 _last_position = _position;
616 if (_position > max_frames - n) {
617 _position = max_frames;
622 if (_position < (nframes_t) -n) {
629 send_change (PositionChanged);
633 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
635 _ancestral_length = l;
636 _ancestral_start = s;
642 Region::set_start (nframes_t pos, void* /*src*/)
644 if (_flags & (Locked|PositionLocked)) {
647 /* This just sets the start, nothing else. It effectively shifts
648 the contents of the Region within the overall extent of the Source,
649 without changing the Region's position or length
654 if (!verify_start (pos)) {
659 _flags = Region::Flag (_flags & ~WholeFile);
661 invalidate_transients ();
663 send_change (StartChanged);
668 Region::trim_start (nframes_t new_position, void */*src*/)
670 if (_flags & (Locked|PositionLocked)) {
676 if (new_position > _position) {
677 start_shift = new_position - _position;
679 start_shift = -(_position - new_position);
682 if (start_shift > 0) {
684 if (_start > max_frames - start_shift) {
685 new_start = max_frames;
687 new_start = _start + start_shift;
690 if (!verify_start (new_start)) {
694 } else if (start_shift < 0) {
696 if (_start < (nframes_t) -start_shift) {
699 new_start = _start + start_shift;
705 if (new_start == _start) {
710 _flags = Region::Flag (_flags & ~WholeFile);
713 send_change (StartChanged);
717 Region::trim_front (nframes_t new_position, void *src)
719 if (_flags & Locked) {
723 nframes_t end = last_frame();
724 nframes_t source_zero;
726 if (_position > _start) {
727 source_zero = _position - _start;
729 source_zero = 0; // its actually negative, but this will work for us
732 if (new_position < end) { /* can't trim it zero or negative length */
736 /* can't trim it back passed where source position zero is located */
738 new_position = max (new_position, source_zero);
741 if (new_position > _position) {
742 newlen = _length - (new_position - _position);
744 newlen = _length + (_position - new_position);
747 trim_to_internal (new_position, newlen, src);
749 recompute_at_start ();
754 /** @param new_endpoint New region end point, such that, for example,
755 * a region at 0 of length 10 has an endpoint of 9.
759 Region::trim_end (nframes_t new_endpoint, void */*src*/)
761 if (_flags & Locked) {
765 if (new_endpoint > _position) {
766 trim_to_internal (_position, new_endpoint - _position + 1, this);
774 Region::trim_to (nframes_t position, nframes_t length, void *src)
776 if (_flags & Locked) {
780 trim_to_internal (position, length, src);
783 recompute_at_start ();
789 Region::trim_to_internal (nframes_t position, nframes_t length, void */*src*/)
794 if (_flags & Locked) {
798 if (position > _position) {
799 start_shift = position - _position;
801 start_shift = -(_position - position);
804 if (start_shift > 0) {
806 if (_start > max_frames - start_shift) {
807 new_start = max_frames;
809 new_start = _start + start_shift;
813 } else if (start_shift < 0) {
815 if (_start < (nframes_t) -start_shift) {
818 new_start = _start + start_shift;
824 if (!verify_start_and_length (new_start, length)) {
828 Change what_changed = Change (0);
830 if (_start != new_start) {
832 what_changed = Change (what_changed|StartChanged);
834 if (_length != length) {
836 _last_length = _length;
839 what_changed = Change (what_changed|LengthChanged);
841 if (_position != position) {
843 _last_position = _position;
845 _position = position;
846 what_changed = Change (what_changed|PositionChanged);
849 _flags = Region::Flag (_flags & ~WholeFile);
851 if (what_changed & (StartChanged|LengthChanged)) {
856 send_change (what_changed);
861 Region::set_hidden (bool yn)
863 if (hidden() != yn) {
866 _flags = Flag (_flags|Hidden);
868 _flags = Flag (_flags & ~Hidden);
871 send_change (HiddenChanged);
876 Region::set_muted (bool yn)
881 _flags = Flag (_flags|Muted);
883 _flags = Flag (_flags & ~Muted);
886 send_change (MuteChanged);
891 Region::set_opaque (bool yn)
893 if (opaque() != yn) {
895 _flags = Flag (_flags|Opaque);
897 _flags = Flag (_flags & ~Opaque);
899 send_change (OpacityChanged);
904 Region::set_locked (bool yn)
906 if (locked() != yn) {
908 _flags = Flag (_flags|Locked);
910 _flags = Flag (_flags & ~Locked);
912 send_change (LockChanged);
917 Region::set_position_locked (bool yn)
919 if (position_locked() != yn) {
921 _flags = Flag (_flags|PositionLocked);
923 _flags = Flag (_flags & ~PositionLocked);
925 send_change (LockChanged);
930 Region::set_sync_position (nframes_t absolute_pos)
932 nframes_t const file_pos = _start + (absolute_pos - _position);
934 if (file_pos != _sync_position) {
936 _sync_position = file_pos;
937 _flags = Flag (_flags|SyncMarked);
942 send_change (SyncOffsetChanged);
947 Region::clear_sync_position ()
949 if (_flags & SyncMarked) {
950 _flags = Flag (_flags & ~SyncMarked);
955 send_change (SyncOffsetChanged);
960 Region::sync_offset (int& dir) const
962 /* returns the sync point relative the first frame of the region */
964 if (_flags & SyncMarked) {
965 if (_sync_position > _start) {
967 return _sync_position - _start;
970 return _start - _sync_position;
979 Region::adjust_to_sync (nframes_t pos) const
982 nframes_t offset = sync_offset (sync_dir);
984 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
993 if (max_frames - pos > offset) {
1002 Region::sync_position() const
1004 if (_flags & SyncMarked) {
1005 return _sync_position;
1014 boost::shared_ptr<Playlist> pl (playlist());
1016 pl->raise_region (shared_from_this ());
1023 boost::shared_ptr<Playlist> pl (playlist());
1025 pl->lower_region (shared_from_this ());
1031 Region::raise_to_top ()
1033 boost::shared_ptr<Playlist> pl (playlist());
1035 pl->raise_region_to_top (shared_from_this());
1040 Region::lower_to_bottom ()
1042 boost::shared_ptr<Playlist> pl (playlist());
1044 pl->lower_region_to_bottom (shared_from_this());
1049 Region::set_layer (layer_t l)
1054 send_change (LayerChanged);
1059 Region::state (bool /*full_state*/)
1061 XMLNode *node = new XMLNode ("Region");
1063 const char* fe = NULL;
1065 _id.print (buf, sizeof (buf));
1066 node->add_property ("id", buf);
1067 node->add_property ("name", _name);
1068 node->add_property ("type", _type.to_string());
1069 snprintf (buf, sizeof (buf), "%u", _start);
1070 node->add_property ("start", buf);
1071 snprintf (buf, sizeof (buf), "%u", _length);
1072 node->add_property ("length", buf);
1073 snprintf (buf, sizeof (buf), "%u", _position);
1074 node->add_property ("position", buf);
1075 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1076 node->add_property ("ancestral-start", buf);
1077 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1078 node->add_property ("ancestral-length", buf);
1079 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1080 node->add_property ("stretch", buf);
1081 snprintf (buf, sizeof (buf), "%.12g", _shift);
1082 node->add_property ("shift", buf);
1084 switch (_first_edit) {
1085 case EditChangesNothing:
1088 case EditChangesName:
1094 default: /* should be unreachable but makes g++ happy */
1099 node->add_property ("first-edit", fe);
1101 /* note: flags are stored by derived classes */
1103 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1104 node->add_property ("layer", buf);
1105 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1106 node->add_property ("sync-position", buf);
1108 if (_positional_lock_style != AudioTime) {
1109 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1112 node->add_property ("bbt-position", str.str());
1119 Region::get_state ()
1121 return state (true);
1125 Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
1127 const XMLNodeList& nlist = node.children();
1128 const XMLProperty *prop;
1131 /* this is responsible for setting those aspects of Region state
1132 that are mutable after construction.
1135 if ((prop = node.property ("name")) == 0) {
1136 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1140 _name = prop->value();
1142 if ((prop = node.property ("type")) == 0) {
1143 _type = DataType::AUDIO;
1145 _type = DataType(prop->value());
1148 if ((prop = node.property ("start")) != 0) {
1149 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1150 if (val != _start) {
1151 what_changed = Change (what_changed|StartChanged);
1158 if ((prop = node.property ("length")) != 0) {
1159 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1160 if (val != _length) {
1161 what_changed = Change (what_changed|LengthChanged);
1162 _last_length = _length;
1166 _last_length = _length;
1170 if ((prop = node.property ("position")) != 0) {
1171 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1172 if (val != _position) {
1173 what_changed = Change (what_changed|PositionChanged);
1174 _last_position = _position;
1178 _last_position = _position;
1182 if ((prop = node.property ("layer")) != 0) {
1184 x = (layer_t) atoi (prop->value().c_str());
1186 what_changed = Change (what_changed|LayerChanged);
1193 if ((prop = node.property ("sync-position")) != 0) {
1194 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1195 if (val != _sync_position) {
1196 what_changed = Change (what_changed|SyncOffsetChanged);
1197 _sync_position = val;
1200 _sync_position = _start;
1203 if ((prop = node.property ("positional-lock-style")) != 0) {
1204 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1206 if (_positional_lock_style == MusicTime) {
1207 if ((prop = node.property ("bbt-position")) == 0) {
1208 /* missing BBT info, revert to audio time locking */
1209 _positional_lock_style = AudioTime;
1211 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1214 &_bbt_time.ticks) != 3) {
1215 _positional_lock_style = AudioTime;
1221 _positional_lock_style = AudioTime;
1224 /* XXX FIRST EDIT !!! */
1226 /* these 3 properties never change as a result of any editing */
1228 if ((prop = node.property ("ancestral-start")) != 0) {
1229 _ancestral_start = strtoll (prop->value().c_str(), 0, 10);
1231 _ancestral_start = _start;
1234 if ((prop = node.property ("ancestral-length")) != 0) {
1235 _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
1237 _ancestral_length = _length;
1240 if ((prop = node.property ("stretch")) != 0) {
1241 _stretch = atof (prop->value());
1243 /* fix problem with old sessions corrupted by an impossible
1246 if (_stretch == 0.0) {
1253 if ((prop = node.property ("shift")) != 0) {
1254 _shift = atof (prop->value());
1256 /* fix problem with old sessions corrupted by an impossible
1259 if (_shift == 0.0) {
1267 /* note: derived classes set flags */
1272 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1278 if (child->name () == "Extra") {
1279 _extra_xml = new XMLNode (*child);
1285 send_change (what_changed);
1292 Region::set_state (const XMLNode& node, int version)
1294 const XMLProperty *prop;
1295 Change what_changed = Change (0);
1297 /* ID is not allowed to change, ever */
1299 if ((prop = node.property ("id")) == 0) {
1300 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1304 _id = prop->value();
1306 _first_edit = EditChangesNothing;
1308 set_live_state (node, version, what_changed, true);
1317 _last_length = _length;
1318 _last_position = _position;
1322 Region::thaw (const string& /*why*/)
1324 Change what_changed = Change (0);
1327 Glib::Mutex::Lock lm (_lock);
1329 if (_frozen && --_frozen > 0) {
1333 if (_pending_changed) {
1334 what_changed = _pending_changed;
1335 _pending_changed = Change (0);
1339 if (what_changed == Change (0)) {
1343 if (what_changed & LengthChanged) {
1344 if (what_changed & PositionChanged) {
1345 recompute_at_start ();
1347 recompute_at_end ();
1350 StateChanged (what_changed);
1354 Region::send_change (Change what_changed)
1357 Glib::Mutex::Lock lm (_lock);
1359 _pending_changed = Change (_pending_changed|what_changed);
1364 StateChanged (what_changed);
1366 if (!(_flags & DoNotSendPropertyChanges)) {
1368 /* Try and send a shared_pointer unless this is part of the constructor.
1373 boost::shared_ptr<Region> rptr = shared_from_this();
1374 RegionPropertyChanged (rptr);
1376 /* no shared_ptr available, relax; */
1383 Region::set_last_layer_op (uint64_t when)
1385 _last_layer_op = when;
1389 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1391 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1395 Region::equivalent (boost::shared_ptr<const Region> other) const
1397 return _start == other->_start &&
1398 _position == other->_position &&
1399 _length == other->_length;
1403 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1405 return _start == other->_start &&
1406 _length == other->_length;
1410 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1412 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1416 Region::source_deleted (boost::weak_ptr<Source>)
1419 cerr << "Send drop ref signal from region " << ' ' << this << endl;
1424 Region::master_source_names ()
1426 SourceList::iterator i;
1428 vector<string> names;
1429 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1430 names.push_back((*i)->name());
1437 Region::set_master_sources (const SourceList& srcs)
1439 _master_sources = srcs;
1440 assert (_sources.size() == _master_sources.size());
1444 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1449 SourceList::const_iterator i;
1450 SourceList::const_iterator io;
1452 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1453 if ((*i)->id() != (*io)->id()) {
1458 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1459 if ((*i)->id() != (*io)->id()) {
1468 Region::uses_source (boost::shared_ptr<const Source> source) const
1470 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1479 Region::source_length(uint32_t n) const
1481 return _sources[n]->length(_position - _start);
1485 Region::verify_length (nframes_t len)
1487 if (source() && (source()->destructive() || source()->length_mutable())) {
1491 nframes_t maxlen = 0;
1493 for (uint32_t n=0; n < _sources.size(); ++n) {
1494 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1497 len = min (len, maxlen);
1503 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1505 if (source() && (source()->destructive() || source()->length_mutable())) {
1509 nframes_t maxlen = 0;
1511 for (uint32_t n=0; n < _sources.size(); ++n) {
1512 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1515 new_length = min (new_length, maxlen);
1521 Region::verify_start (nframes_t pos)
1523 if (source() && (source()->destructive() || source()->length_mutable())) {
1527 for (uint32_t n=0; n < _sources.size(); ++n) {
1528 if (pos > source_length(n) - _length) {
1536 Region::verify_start_mutable (nframes_t& new_start)
1538 if (source() && (source()->destructive() || source()->length_mutable())) {
1542 for (uint32_t n=0; n < _sources.size(); ++n) {
1543 if (new_start > source_length(n) - _length) {
1544 new_start = source_length(n) - _length;
1550 boost::shared_ptr<Region>
1551 Region::get_parent() const
1553 boost::shared_ptr<Playlist> pl (playlist());
1556 boost::shared_ptr<Region> r;
1557 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1559 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1560 return boost::static_pointer_cast<Region> (r);
1564 return boost::shared_ptr<Region>();
1568 Region::apply (Filter& filter)
1570 return filter.run (shared_from_this());
1575 Region::invalidate_transients ()
1577 _valid_transients = false;
1578 _transients.clear ();
1583 Region::use_sources (SourceList const & s)
1585 set<boost::shared_ptr<Source> > unique_srcs;
1587 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1588 _sources.push_back (*i);
1589 scoped_connect ((*i)->GoingAway, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1590 unique_srcs.insert (*i);
1593 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1594 _master_sources.push_back (*i);
1595 if (unique_srcs.find (*i) == unique_srcs.end()) {
1596 scoped_connect ((*i)->GoingAway, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));