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 PBD::Signal1<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 src->DropReferences.connect_same_thread (*this, 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));
344 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
347 _pending_changed = Change (0);
348 _read_data_count = 0;
349 _valid_transients = false;
352 _last_length = length;
353 _sync_position = other->_sync_position;
354 _ancestral_start = other->_ancestral_start;
355 _ancestral_length = other->_ancestral_length;
356 _stretch = other->_stretch;
357 _shift = other->_shift;
362 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
363 _first_edit = EditChangesNothing;
365 _positional_lock_style = AudioTime;
367 use_sources (other->_sources);
371 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
373 _playlist = wpl.lock();
377 Region::set_name (const std::string& str)
380 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
381 assert(_name == str);
382 send_change (ARDOUR::NameChanged);
389 Region::set_length (nframes_t len, void */*src*/)
391 //cerr << "Region::set_length() len = " << len << endl;
392 if (_flags & Locked) {
396 if (_length != len && len != 0) {
398 /* check that the current _position wouldn't make the new
402 if (max_frames - len < _position) {
406 if (!verify_length (len)) {
411 _last_length = _length;
414 _flags = Region::Flag (_flags & ~WholeFile);
418 invalidate_transients ();
424 send_change (LengthChanged);
429 Region::maybe_uncopy ()
434 Region::first_edit ()
436 boost::shared_ptr<Playlist> pl (playlist());
438 if (_first_edit != EditChangesNothing && pl) {
440 _name = _session.new_region_name (_name);
441 _first_edit = EditChangesNothing;
443 send_change (ARDOUR::NameChanged);
444 RegionFactory::CheckNewRegion (shared_from_this());
449 Region::at_natural_position () const
451 boost::shared_ptr<Playlist> pl (playlist());
457 boost::shared_ptr<Region> whole_file_region = get_parent();
459 if (whole_file_region) {
460 if (_position == whole_file_region->position() + _start) {
469 Region::move_to_natural_position (void *src)
471 boost::shared_ptr<Playlist> pl (playlist());
477 boost::shared_ptr<Region> whole_file_region = get_parent();
479 if (whole_file_region) {
480 set_position (whole_file_region->position() + _start, src);
485 Region::special_set_position (nframes_t pos)
487 /* this is used when creating a whole file region as
488 a way to store its "natural" or "captured" position.
491 _position = _position;
496 Region::set_position_lock_style (PositionLockStyle ps)
498 boost::shared_ptr<Playlist> pl (playlist());
504 _positional_lock_style = ps;
506 if (_positional_lock_style == MusicTime) {
507 _session.tempo_map().bbt_time (_position, _bbt_time);
513 Region::update_position_after_tempo_map_change ()
515 boost::shared_ptr<Playlist> pl (playlist());
517 if (!pl || _positional_lock_style != MusicTime) {
521 TempoMap& map (_session.tempo_map());
522 nframes_t pos = map.frame_time (_bbt_time);
523 set_position_internal (pos, false);
527 Region::set_position (nframes_t pos, void* /*src*/)
533 set_position_internal (pos, true);
537 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
539 if (_position != pos) {
540 _last_position = _position;
543 /* check that the new _position wouldn't make the current
544 length impossible - if so, change the length.
546 XXX is this the right thing to do?
549 if (max_frames - _length < _position) {
550 _last_length = _length;
551 _length = max_frames - _position;
554 if (allow_bbt_recompute) {
555 recompute_position_from_lock_style ();
558 invalidate_transients ();
561 /* do this even if the position is the same. this helps out
562 a GUI that has moved its representation already.
565 send_change (PositionChanged);
569 Region::set_position_on_top (nframes_t pos, void* /*src*/)
571 if (_flags & Locked) {
575 if (_position != pos) {
576 _last_position = _position;
580 boost::shared_ptr<Playlist> pl (playlist());
583 pl->raise_region_to_top (shared_from_this ());
586 /* do this even if the position is the same. this helps out
587 a GUI that has moved its representation already.
590 send_change (PositionChanged);
594 Region::recompute_position_from_lock_style ()
596 if (_positional_lock_style == MusicTime) {
597 _session.tempo_map().bbt_time (_position, _bbt_time);
602 Region::nudge_position (nframes64_t n, void* /*src*/)
604 if (_flags & Locked) {
612 _last_position = _position;
615 if (_position > max_frames - n) {
616 _position = max_frames;
621 if (_position < (nframes_t) -n) {
628 send_change (PositionChanged);
632 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
634 _ancestral_length = l;
635 _ancestral_start = s;
641 Region::set_start (nframes_t pos, void* /*src*/)
643 if (_flags & (Locked|PositionLocked)) {
646 /* This just sets the start, nothing else. It effectively shifts
647 the contents of the Region within the overall extent of the Source,
648 without changing the Region's position or length
653 if (!verify_start (pos)) {
658 _flags = Region::Flag (_flags & ~WholeFile);
660 invalidate_transients ();
662 send_change (StartChanged);
667 Region::trim_start (nframes_t new_position, void */*src*/)
669 if (_flags & (Locked|PositionLocked)) {
675 if (new_position > _position) {
676 start_shift = new_position - _position;
678 start_shift = -(_position - new_position);
681 if (start_shift > 0) {
683 if (_start > max_frames - start_shift) {
684 new_start = max_frames;
686 new_start = _start + start_shift;
689 if (!verify_start (new_start)) {
693 } else if (start_shift < 0) {
695 if (_start < (nframes_t) -start_shift) {
698 new_start = _start + start_shift;
704 if (new_start == _start) {
709 _flags = Region::Flag (_flags & ~WholeFile);
712 send_change (StartChanged);
716 Region::trim_front (nframes_t new_position, void *src)
718 if (_flags & Locked) {
722 nframes_t end = last_frame();
723 nframes_t source_zero;
725 if (_position > _start) {
726 source_zero = _position - _start;
728 source_zero = 0; // its actually negative, but this will work for us
731 if (new_position < end) { /* can't trim it zero or negative length */
735 /* can't trim it back passed where source position zero is located */
737 new_position = max (new_position, source_zero);
740 if (new_position > _position) {
741 newlen = _length - (new_position - _position);
743 newlen = _length + (_position - new_position);
746 trim_to_internal (new_position, newlen, src);
748 recompute_at_start ();
753 /** @param new_endpoint New region end point, such that, for example,
754 * a region at 0 of length 10 has an endpoint of 9.
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 + 1, 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)
931 nframes_t const file_pos = _start + (absolute_pos - _position);
933 if (file_pos != _sync_position) {
935 _sync_position = file_pos;
936 _flags = Flag (_flags|SyncMarked);
941 send_change (SyncOffsetChanged);
946 Region::clear_sync_position ()
948 if (_flags & SyncMarked) {
949 _flags = Flag (_flags & ~SyncMarked);
954 send_change (SyncOffsetChanged);
959 Region::sync_offset (int& dir) const
961 /* returns the sync point relative the first frame of the region */
963 if (_flags & SyncMarked) {
964 if (_sync_position > _start) {
966 return _sync_position - _start;
969 return _start - _sync_position;
978 Region::adjust_to_sync (nframes_t pos) const
981 nframes_t offset = sync_offset (sync_dir);
983 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
992 if (max_frames - pos > offset) {
1001 Region::sync_position() const
1003 if (_flags & SyncMarked) {
1004 return _sync_position;
1013 boost::shared_ptr<Playlist> pl (playlist());
1015 pl->raise_region (shared_from_this ());
1022 boost::shared_ptr<Playlist> pl (playlist());
1024 pl->lower_region (shared_from_this ());
1030 Region::raise_to_top ()
1032 boost::shared_ptr<Playlist> pl (playlist());
1034 pl->raise_region_to_top (shared_from_this());
1039 Region::lower_to_bottom ()
1041 boost::shared_ptr<Playlist> pl (playlist());
1043 pl->lower_region_to_bottom (shared_from_this());
1048 Region::set_layer (layer_t l)
1053 send_change (LayerChanged);
1058 Region::state (bool /*full_state*/)
1060 XMLNode *node = new XMLNode ("Region");
1062 const char* fe = NULL;
1064 _id.print (buf, sizeof (buf));
1065 node->add_property ("id", buf);
1066 node->add_property ("name", _name);
1067 node->add_property ("type", _type.to_string());
1068 snprintf (buf, sizeof (buf), "%u", _start);
1069 node->add_property ("start", buf);
1070 snprintf (buf, sizeof (buf), "%u", _length);
1071 node->add_property ("length", buf);
1072 snprintf (buf, sizeof (buf), "%u", _position);
1073 node->add_property ("position", buf);
1074 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1075 node->add_property ("ancestral-start", buf);
1076 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1077 node->add_property ("ancestral-length", buf);
1078 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1079 node->add_property ("stretch", buf);
1080 snprintf (buf, sizeof (buf), "%.12g", _shift);
1081 node->add_property ("shift", buf);
1083 switch (_first_edit) {
1084 case EditChangesNothing:
1087 case EditChangesName:
1093 default: /* should be unreachable but makes g++ happy */
1098 node->add_property ("first-edit", fe);
1100 /* note: flags are stored by derived classes */
1102 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1103 node->add_property ("layer", buf);
1104 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1105 node->add_property ("sync-position", buf);
1107 if (_positional_lock_style != AudioTime) {
1108 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1111 node->add_property ("bbt-position", str.str());
1118 Region::get_state ()
1120 return state (true);
1124 Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
1126 const XMLNodeList& nlist = node.children();
1127 const XMLProperty *prop;
1130 /* this is responsible for setting those aspects of Region state
1131 that are mutable after construction.
1134 if ((prop = node.property ("name")) == 0) {
1135 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1139 _name = prop->value();
1141 if ((prop = node.property ("type")) == 0) {
1142 _type = DataType::AUDIO;
1144 _type = DataType(prop->value());
1147 if ((prop = node.property ("start")) != 0) {
1148 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1149 if (val != _start) {
1150 what_changed = Change (what_changed|StartChanged);
1151 cerr << _name << " start changed\n";
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 cerr << _name << " length changed\n";
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 cerr << _name << " position changed\n";
1176 _last_position = _position;
1180 _last_position = _position;
1184 if ((prop = node.property ("layer")) != 0) {
1186 x = (layer_t) atoi (prop->value().c_str());
1188 what_changed = Change (what_changed|LayerChanged);
1189 cerr << _name << " layer changed\n";
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 cerr << _name << " sync changed\n";
1201 _sync_position = val;
1204 _sync_position = _start;
1207 if ((prop = node.property ("positional-lock-style")) != 0) {
1208 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1210 if (_positional_lock_style == MusicTime) {
1211 if ((prop = node.property ("bbt-position")) == 0) {
1212 /* missing BBT info, revert to audio time locking */
1213 _positional_lock_style = AudioTime;
1215 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1218 &_bbt_time.ticks) != 3) {
1219 _positional_lock_style = AudioTime;
1225 _positional_lock_style = AudioTime;
1228 /* XXX FIRST EDIT !!! */
1230 /* these 3 properties never change as a result of any editing */
1232 if ((prop = node.property ("ancestral-start")) != 0) {
1233 _ancestral_start = strtoll (prop->value().c_str(), 0, 10);
1235 _ancestral_start = _start;
1238 if ((prop = node.property ("ancestral-length")) != 0) {
1239 _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
1241 _ancestral_length = _length;
1244 if ((prop = node.property ("stretch")) != 0) {
1245 _stretch = atof (prop->value());
1247 /* fix problem with old sessions corrupted by an impossible
1250 if (_stretch == 0.0) {
1257 if ((prop = node.property ("shift")) != 0) {
1258 _shift = atof (prop->value());
1260 /* fix problem with old sessions corrupted by an impossible
1263 if (_shift == 0.0) {
1271 /* note: derived classes set flags */
1276 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1282 if (child->name () == "Extra") {
1283 _extra_xml = new XMLNode (*child);
1289 cerr << _name << ": final change to be sent: " << hex << what_changed << dec << endl;
1290 send_change (what_changed);
1297 Region::set_state (const XMLNode& node, int version)
1299 const XMLProperty *prop;
1300 Change what_changed = Change (0);
1302 /* ID is not allowed to change, ever */
1304 if ((prop = node.property ("id")) == 0) {
1305 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1309 _id = prop->value();
1311 _first_edit = EditChangesNothing;
1313 set_live_state (node, version, what_changed, true);
1322 _last_length = _length;
1323 _last_position = _position;
1327 Region::thaw (const string& /*why*/)
1329 Change what_changed = Change (0);
1332 Glib::Mutex::Lock lm (_lock);
1334 if (_frozen && --_frozen > 0) {
1338 if (_pending_changed) {
1339 what_changed = _pending_changed;
1340 _pending_changed = Change (0);
1344 if (what_changed == Change (0)) {
1348 if (what_changed & LengthChanged) {
1349 if (what_changed & PositionChanged) {
1350 recompute_at_start ();
1352 recompute_at_end ();
1355 send_change (what_changed);
1359 Region::send_change (Change what_changed)
1363 Glib::Mutex::Lock lm (_lock);
1365 _pending_changed = Change (_pending_changed|what_changed);
1370 cerr << _name << " actually sends " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1371 StateChanged (what_changed);
1372 cerr << _name << " done with " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1374 if (!(_flags & DoNotSendPropertyChanges)) {
1376 /* Try and send a shared_pointer unless this is part of the constructor.
1381 boost::shared_ptr<Region> rptr = shared_from_this();
1382 cerr << _name << " actually sends prop change " << hex << what_changed << dec << " @ " << get_microseconds() << endl;
1383 RegionPropertyChanged (rptr);
1384 cerr << _name << " done with prop change @ " << get_microseconds() << endl;
1386 /* no shared_ptr available, relax; */
1393 Region::set_last_layer_op (uint64_t when)
1395 _last_layer_op = when;
1399 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1401 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1405 Region::equivalent (boost::shared_ptr<const Region> other) const
1407 return _start == other->_start &&
1408 _position == other->_position &&
1409 _length == other->_length;
1413 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1415 return _start == other->_start &&
1416 _length == other->_length;
1420 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1422 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1426 Region::source_deleted (boost::weak_ptr<Source>)
1430 if (!_session.deletion_in_progress()) {
1431 /* this is a very special case: at least one of the region's
1432 sources has bee deleted, so invalidate all references to
1433 ourselves. Do NOT do this during session deletion, because
1434 then we run the risk that this will actually result
1435 in this object being deleted (as refcnt goes to zero)
1436 while emitting DropReferences.
1444 Region::master_source_names ()
1446 SourceList::iterator i;
1448 vector<string> names;
1449 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1450 names.push_back((*i)->name());
1457 Region::set_master_sources (const SourceList& srcs)
1459 _master_sources = srcs;
1460 assert (_sources.size() == _master_sources.size());
1464 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1469 SourceList::const_iterator i;
1470 SourceList::const_iterator io;
1472 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1473 if ((*i)->id() != (*io)->id()) {
1478 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1479 if ((*i)->id() != (*io)->id()) {
1488 Region::uses_source (boost::shared_ptr<const Source> source) const
1490 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1499 Region::source_length(uint32_t n) const
1501 return _sources[n]->length(_position - _start);
1505 Region::verify_length (nframes_t len)
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) - _start);
1517 len = min (len, maxlen);
1523 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1525 if (source() && (source()->destructive() || source()->length_mutable())) {
1529 nframes_t maxlen = 0;
1531 for (uint32_t n=0; n < _sources.size(); ++n) {
1532 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1535 new_length = min (new_length, maxlen);
1541 Region::verify_start (nframes_t pos)
1543 if (source() && (source()->destructive() || source()->length_mutable())) {
1547 for (uint32_t n=0; n < _sources.size(); ++n) {
1548 if (pos > source_length(n) - _length) {
1556 Region::verify_start_mutable (nframes_t& new_start)
1558 if (source() && (source()->destructive() || source()->length_mutable())) {
1562 for (uint32_t n=0; n < _sources.size(); ++n) {
1563 if (new_start > source_length(n) - _length) {
1564 new_start = source_length(n) - _length;
1570 boost::shared_ptr<Region>
1571 Region::get_parent() const
1573 boost::shared_ptr<Playlist> pl (playlist());
1576 boost::shared_ptr<Region> r;
1577 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1579 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1580 return boost::static_pointer_cast<Region> (r);
1584 return boost::shared_ptr<Region>();
1588 Region::apply (Filter& filter)
1590 return filter.run (shared_from_this());
1595 Region::invalidate_transients ()
1597 _valid_transients = false;
1598 _transients.clear ();
1603 Region::use_sources (SourceList const & s)
1605 set<boost::shared_ptr<Source> > unique_srcs;
1607 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1608 _sources.push_back (*i);
1609 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1610 unique_srcs.insert (*i);
1613 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1614 _master_sources.push_back (*i);
1615 if (unique_srcs.find (*i) == unique_srcs.end()) {
1616 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));