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;
60 Region::register_states ()
62 _xml_node_name = X_("Region");
64 add_state (_position);
68 /* derived-from-derived constructor (no sources in constructor) */
69 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
70 : SessionObject(s, name)
72 , _flags(Flag (flags|DoNotSendPropertyChanges))
73 , _start (X_("start"), start)
75 , _position (X_("position"), 0)
77 , _positional_lock_style(AudioTime)
78 , _sync_position(_start)
79 , _layer (X_("layer"), layer)
80 , _first_edit(EditChangesNothing)
82 , _ancestral_start (0)
83 , _ancestral_length (0)
87 , _pending_changed(Change (0))
89 , _pending_explicit_relayer (false)
93 /* no sources at this point */
96 /** Basic Region constructor (single source) */
97 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
98 : SessionObject(src->session(), name)
100 , _flags(Flag (flags|DoNotSendPropertyChanges))
101 , _start (X_("start"), start)
103 , _position (X_("position"), 0)
105 , _positional_lock_style(AudioTime)
106 , _sync_position(_start)
107 , _layer (X_("layer"), layer)
108 , _first_edit(EditChangesNothing)
110 , _ancestral_start (0)
111 , _ancestral_length (0)
114 , _valid_transients(false)
115 , _read_data_count(0)
116 , _pending_changed(Change (0))
118 , _pending_explicit_relayer (false)
122 _sources.push_back (src);
123 _master_sources.push_back (src);
125 src->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
127 assert(_sources.size() > 0);
128 _positional_lock_style = AudioTime;
131 /** Basic Region constructor (many sources) */
132 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
133 : SessionObject(srcs.front()->session(), name)
135 , _flags(Flag (flags|DoNotSendPropertyChanges))
136 , _start (X_("start"), start)
138 , _position (X_("position"), 0)
140 , _positional_lock_style(AudioTime)
141 , _sync_position(_start)
142 , _layer (X_("layer"), layer)
143 , _first_edit(EditChangesNothing)
145 , _ancestral_start (0)
146 , _ancestral_length (0)
149 , _read_data_count(0)
150 , _pending_changed(Change (0))
152 , _pending_explicit_relayer (false)
157 assert(_sources.size() > 0);
160 /** Create a new Region from part of an existing one */
161 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
162 : SessionObject(other->session(), name)
163 , _type (other->data_type())
164 , _start (X_("start"), 0)
165 , _position (X_("position"), 0)
166 , _layer (X_("layer"), 0)
167 , _pending_explicit_relayer (false)
172 _start = other->_start + offset;
173 copy_stuff (other, offset, length, name, layer, flags);
175 _flags = Flag (_flags | DoNotSendPropertyChanges);
177 /* if the other region had a distinct sync point
178 set, then continue to use it as best we can.
179 otherwise, reset sync point back to start.
182 if (other->flags() & SyncMarked) {
183 if (other->_sync_position < _start) {
184 _flags = Flag (_flags & ~SyncMarked);
185 _sync_position = _start;
187 _sync_position = other->_sync_position;
190 _flags = Flag (_flags & ~SyncMarked);
191 _sync_position = _start;
194 if (Profile->get_sae()) {
195 /* reset sync point to start if its ended up
196 outside region bounds.
199 if (_sync_position < _start || _sync_position >= _start + _length) {
200 _flags = Flag (_flags & ~SyncMarked);
201 _sync_position = _start;
206 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
207 : SessionObject(other->session(), name)
208 , _type (other->data_type())
209 , _start (X_("start"), 0)
210 , _position (X_("position"), 0)
211 , _layer (X_("layer"), 0)
212 , _pending_explicit_relayer (false)
216 /* create a new Region exactly like another but starting at 0 in its sources */
219 copy_stuff (other, 0, length, name, layer, flags);
221 _flags = Flag (_flags | DoNotSendPropertyChanges);
223 /* sync pos is relative to start of file. our start-in-file is now zero,
224 so set our sync position to whatever the the difference between
225 _start and _sync_pos was in the other region.
227 result is that our new sync pos points to the same point in our source(s)
228 as the sync in the other region did in its source(s).
230 since we start at zero in our source(s), it is not possible to use a sync point that
231 is before the start. reset it to _start if that was true in the other region.
234 if (other->flags() & SyncMarked) {
235 if (other->_start < other->_sync_position) {
236 /* sync pos was after the start point of the other region */
237 _sync_position = other->_sync_position - other->_start;
239 /* sync pos was before the start point of the other region. not possible here. */
240 _flags = Flag (_flags & ~SyncMarked);
241 _sync_position = _start;
244 _flags = Flag (_flags & ~SyncMarked);
245 _sync_position = _start;
248 if (Profile->get_sae()) {
249 /* reset sync point to start if its ended up
250 outside region bounds.
253 if (_sync_position < _start || _sync_position >= _start + _length) {
254 _flags = Flag (_flags & ~SyncMarked);
255 _sync_position = _start;
259 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
261 _positional_lock_style = other->_positional_lock_style;
262 _first_edit = other->_first_edit;
265 /** Pure copy constructor */
266 Region::Region (boost::shared_ptr<const Region> other)
267 : SessionObject(other->session(), other->name())
268 , _type(other->data_type())
269 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
270 , _start(other->_start)
271 , _length(other->_length)
272 , _position(other->_position)
273 , _last_position(other->_last_position)
274 , _positional_lock_style(other->_positional_lock_style)
275 , _sync_position(other->_sync_position)
276 , _layer(other->_layer)
277 , _first_edit(EditChangesID)
279 , _ancestral_start (other->_ancestral_start)
280 , _ancestral_length (other->_ancestral_length)
281 , _stretch (other->_stretch)
282 , _shift (other->_shift)
283 , _valid_transients(false)
284 , _read_data_count(0)
285 , _pending_changed(Change(0))
286 , _last_layer_op(other->_last_layer_op)
287 , _pending_explicit_relayer (false)
291 _flags = Flag (_flags | DoNotSendPropertyChanges);
293 other->_first_edit = EditChangesName;
295 if (other->_extra_xml) {
296 _extra_xml = new XMLNode (*other->_extra_xml);
301 use_sources (other->_sources);
302 assert(_sources.size() > 0);
305 Region::Region (const SourceList& srcs, const XMLNode& node)
306 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
307 , _type(DataType::NIL) // to be loaded from XML
308 , _flags(DoNotSendPropertyChanges)
309 , _start (X_("start"), 0)
311 , _position (X_("position"), 0)
313 , _positional_lock_style(AudioTime)
314 , _sync_position(_start)
315 , _layer (X_("layer"), 0)
316 , _first_edit(EditChangesNothing)
320 , _read_data_count(0)
321 , _pending_changed(Change(0))
323 , _pending_explicit_relayer (false)
329 if (set_state (node, Stateful::loading_state_version)) {
330 throw failed_constructor();
333 assert(_type != DataType::NIL);
334 assert(_sources.size() > 0);
337 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
338 : SessionObject(src->session(), X_("error: XML did not reset this"))
339 , _type(DataType::NIL)
340 , _flags(DoNotSendPropertyChanges)
341 , _start (X_("start"), 0)
343 , _position (X_("position"), 0)
345 , _positional_lock_style(AudioTime)
346 , _sync_position(_start)
347 , _layer (X_("layer"), 0)
348 , _first_edit(EditChangesNothing)
352 , _read_data_count(0)
353 , _pending_changed(Change(0))
355 , _pending_explicit_relayer (false)
359 _sources.push_back (src);
361 if (set_state (node, Stateful::loading_state_version)) {
362 throw failed_constructor();
365 assert(_type != DataType::NIL);
366 assert(_sources.size() > 0);
371 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
375 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
378 _pending_changed = Change (0);
379 _read_data_count = 0;
380 _valid_transients = false;
383 _last_length = length;
384 _sync_position = other->_sync_position;
385 _ancestral_start = other->_ancestral_start;
386 _ancestral_length = other->_ancestral_length;
387 _stretch = other->_stretch;
388 _shift = other->_shift;
393 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
394 _first_edit = EditChangesNothing;
396 _positional_lock_style = AudioTime;
398 use_sources (other->_sources);
402 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
404 _playlist = wpl.lock();
408 Region::set_name (const std::string& str)
411 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
412 assert(_name == str);
413 send_change (ARDOUR::NameChanged);
420 Region::set_length (nframes_t len, void */*src*/)
422 //cerr << "Region::set_length() len = " << len << endl;
423 if (_flags & Locked) {
427 if (_length != len && len != 0) {
429 /* check that the current _position wouldn't make the new
433 if (max_frames - len < _position) {
437 if (!verify_length (len)) {
442 _last_length = _length;
445 _flags = Region::Flag (_flags & ~WholeFile);
449 invalidate_transients ();
455 send_change (LengthChanged);
460 Region::maybe_uncopy ()
465 Region::first_edit ()
467 boost::shared_ptr<Playlist> pl (playlist());
469 if (_first_edit != EditChangesNothing && pl) {
471 _name = _session.new_region_name (_name);
472 _first_edit = EditChangesNothing;
474 send_change (ARDOUR::NameChanged);
475 RegionFactory::CheckNewRegion (shared_from_this());
480 Region::at_natural_position () const
482 boost::shared_ptr<Playlist> pl (playlist());
488 boost::shared_ptr<Region> whole_file_region = get_parent();
490 if (whole_file_region) {
491 if (_position == whole_file_region->position() + _start) {
500 Region::move_to_natural_position (void *src)
502 boost::shared_ptr<Playlist> pl (playlist());
508 boost::shared_ptr<Region> whole_file_region = get_parent();
510 if (whole_file_region) {
511 set_position (whole_file_region->position() + _start, src);
516 Region::special_set_position (nframes_t pos)
518 /* this is used when creating a whole file region as
519 a way to store its "natural" or "captured" position.
522 _position = _position;
527 Region::set_position_lock_style (PositionLockStyle ps)
529 boost::shared_ptr<Playlist> pl (playlist());
535 _positional_lock_style = ps;
537 if (_positional_lock_style == MusicTime) {
538 _session.tempo_map().bbt_time (_position, _bbt_time);
544 Region::update_position_after_tempo_map_change ()
546 boost::shared_ptr<Playlist> pl (playlist());
548 if (!pl || _positional_lock_style != MusicTime) {
552 TempoMap& map (_session.tempo_map());
553 nframes_t pos = map.frame_time (_bbt_time);
554 set_position_internal (pos, false);
558 Region::set_position (nframes_t pos, void* /*src*/)
564 set_position_internal (pos, true);
568 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
570 if (_position != pos) {
571 _last_position = _position;
574 /* check that the new _position wouldn't make the current
575 length impossible - if so, change the length.
577 XXX is this the right thing to do?
580 if (max_frames - _length < _position) {
581 _last_length = _length;
582 _length = max_frames - _position;
585 if (allow_bbt_recompute) {
586 recompute_position_from_lock_style ();
589 invalidate_transients ();
592 /* do this even if the position is the same. this helps out
593 a GUI that has moved its representation already.
596 send_change (PositionChanged);
600 Region::set_position_on_top (nframes_t pos, void* /*src*/)
602 if (_flags & Locked) {
606 if (_position != pos) {
607 _last_position = _position;
611 boost::shared_ptr<Playlist> pl (playlist());
614 pl->raise_region_to_top (shared_from_this ());
617 /* do this even if the position is the same. this helps out
618 a GUI that has moved its representation already.
621 send_change (PositionChanged);
625 Region::recompute_position_from_lock_style ()
627 if (_positional_lock_style == MusicTime) {
628 _session.tempo_map().bbt_time (_position, _bbt_time);
633 Region::nudge_position (nframes64_t n, void* /*src*/)
635 if (_flags & Locked) {
643 _last_position = _position;
646 if (_position > max_frames - n) {
647 _position = max_frames;
652 if (_position < (nframes_t) -n) {
659 send_change (PositionChanged);
663 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
665 _ancestral_length = l;
666 _ancestral_start = s;
672 Region::set_start (nframes_t pos, void* /*src*/)
674 if (_flags & (Locked|PositionLocked)) {
677 /* This just sets the start, nothing else. It effectively shifts
678 the contents of the Region within the overall extent of the Source,
679 without changing the Region's position or length
684 if (!verify_start (pos)) {
689 _flags = Region::Flag (_flags & ~WholeFile);
691 invalidate_transients ();
693 send_change (StartChanged);
698 Region::trim_start (nframes_t new_position, void */*src*/)
700 if (_flags & (Locked|PositionLocked)) {
706 if (new_position > _position) {
707 start_shift = new_position - _position;
709 start_shift = -(_position - new_position);
712 if (start_shift > 0) {
714 if (_start > max_frames - start_shift) {
715 new_start = max_frames;
717 new_start = _start + start_shift;
720 if (!verify_start (new_start)) {
724 } else if (start_shift < 0) {
726 if (_start < (nframes_t) -start_shift) {
729 new_start = _start + start_shift;
735 if (new_start == _start) {
740 _flags = Region::Flag (_flags & ~WholeFile);
743 send_change (StartChanged);
747 Region::trim_front (nframes_t new_position, void *src)
749 if (_flags & Locked) {
753 nframes_t end = last_frame();
754 nframes_t source_zero;
756 if (_position > _start) {
757 source_zero = _position - _start;
759 source_zero = 0; // its actually negative, but this will work for us
762 if (new_position < end) { /* can't trim it zero or negative length */
766 /* can't trim it back passed where source position zero is located */
768 new_position = max (new_position, source_zero);
771 if (new_position > _position) {
772 newlen = _length - (new_position - _position);
774 newlen = _length + (_position - new_position);
777 trim_to_internal (new_position, newlen, src);
779 recompute_at_start ();
784 /** @param new_endpoint New region end point, such that, for example,
785 * a region at 0 of length 10 has an endpoint of 9.
789 Region::trim_end (nframes_t new_endpoint, void */*src*/)
791 if (_flags & Locked) {
795 if (new_endpoint > _position) {
796 trim_to_internal (_position, new_endpoint - _position + 1, this);
804 Region::trim_to (nframes_t position, nframes_t length, void *src)
806 if (_flags & Locked) {
810 trim_to_internal (position, length, src);
813 recompute_at_start ();
819 Region::trim_to_internal (nframes_t position, nframes_t length, void */*src*/)
824 if (_flags & Locked) {
828 if (position > _position) {
829 start_shift = position - _position;
831 start_shift = -(_position - position);
834 if (start_shift > 0) {
836 if (_start > max_frames - start_shift) {
837 new_start = max_frames;
839 new_start = _start + start_shift;
843 } else if (start_shift < 0) {
845 if (_start < (nframes_t) -start_shift) {
848 new_start = _start + start_shift;
854 if (!verify_start_and_length (new_start, length)) {
858 Change what_changed = Change (0);
860 if (_start != new_start) {
862 what_changed = Change (what_changed|StartChanged);
864 if (_length != length) {
866 _last_length = _length;
869 what_changed = Change (what_changed|LengthChanged);
871 if (_position != position) {
873 _last_position = _position;
875 _position = position;
876 what_changed = Change (what_changed|PositionChanged);
879 _flags = Region::Flag (_flags & ~WholeFile);
881 if (what_changed & (StartChanged|LengthChanged)) {
886 send_change (what_changed);
891 Region::set_hidden (bool yn)
893 if (hidden() != yn) {
896 _flags = Flag (_flags|Hidden);
898 _flags = Flag (_flags & ~Hidden);
901 send_change (HiddenChanged);
906 Region::set_muted (bool yn)
911 _flags = Flag (_flags|Muted);
913 _flags = Flag (_flags & ~Muted);
916 send_change (MuteChanged);
921 Region::set_opaque (bool yn)
923 if (opaque() != yn) {
925 _flags = Flag (_flags|Opaque);
927 _flags = Flag (_flags & ~Opaque);
929 send_change (OpacityChanged);
934 Region::set_locked (bool yn)
936 if (locked() != yn) {
938 _flags = Flag (_flags|Locked);
940 _flags = Flag (_flags & ~Locked);
942 send_change (LockChanged);
947 Region::set_position_locked (bool yn)
949 if (position_locked() != yn) {
951 _flags = Flag (_flags|PositionLocked);
953 _flags = Flag (_flags & ~PositionLocked);
955 send_change (LockChanged);
960 Region::set_sync_position (nframes_t absolute_pos)
962 nframes_t const file_pos = _start + (absolute_pos - _position);
964 if (file_pos != _sync_position) {
966 _sync_position = file_pos;
967 _flags = Flag (_flags|SyncMarked);
972 send_change (SyncOffsetChanged);
977 Region::clear_sync_position ()
979 if (_flags & SyncMarked) {
980 _flags = Flag (_flags & ~SyncMarked);
985 send_change (SyncOffsetChanged);
990 Region::sync_offset (int& dir) const
992 /* returns the sync point relative the first frame of the region */
994 if (_flags & SyncMarked) {
995 if (_sync_position > _start) {
997 return _sync_position - _start;
1000 return _start - _sync_position;
1009 Region::adjust_to_sync (nframes_t pos) const
1012 nframes_t offset = sync_offset (sync_dir);
1014 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1023 if (max_frames - pos > offset) {
1032 Region::sync_position() const
1034 if (_flags & SyncMarked) {
1035 return _sync_position;
1044 boost::shared_ptr<Playlist> pl (playlist());
1046 pl->raise_region (shared_from_this ());
1053 boost::shared_ptr<Playlist> pl (playlist());
1055 pl->lower_region (shared_from_this ());
1061 Region::raise_to_top ()
1063 boost::shared_ptr<Playlist> pl (playlist());
1065 pl->raise_region_to_top (shared_from_this());
1070 Region::lower_to_bottom ()
1072 boost::shared_ptr<Playlist> pl (playlist());
1074 pl->lower_region_to_bottom (shared_from_this());
1079 Region::set_layer (layer_t l)
1084 send_change (LayerChanged);
1089 Region::state (bool /*full_state*/)
1091 XMLNode *node = new XMLNode ("Region");
1093 const char* fe = NULL;
1095 _id.print (buf, sizeof (buf));
1096 node->add_property ("id", buf);
1097 node->add_property ("name", _name);
1098 node->add_property ("type", _type.to_string());
1099 snprintf (buf, sizeof (buf), "%u", _start.get ());
1100 node->add_property ("start", buf);
1101 snprintf (buf, sizeof (buf), "%u", _length);
1102 node->add_property ("length", buf);
1103 snprintf (buf, sizeof (buf), "%u", _position.get ());
1104 node->add_property ("position", buf);
1105 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1106 node->add_property ("ancestral-start", buf);
1107 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1108 node->add_property ("ancestral-length", buf);
1109 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1110 node->add_property ("stretch", buf);
1111 snprintf (buf, sizeof (buf), "%.12g", _shift);
1112 node->add_property ("shift", buf);
1114 switch (_first_edit) {
1115 case EditChangesNothing:
1118 case EditChangesName:
1124 default: /* should be unreachable but makes g++ happy */
1129 node->add_property ("first-edit", fe);
1131 /* note: flags are stored by derived classes */
1133 snprintf (buf, sizeof (buf), "%d", (int) _layer.get());
1134 node->add_property ("layer", buf);
1135 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1136 node->add_property ("sync-position", buf);
1138 if (_positional_lock_style != AudioTime) {
1139 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1142 node->add_property ("bbt-position", str.str());
1149 Region::get_state ()
1151 return state (true);
1155 Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
1157 const XMLNodeList& nlist = node.children();
1158 const XMLProperty *prop;
1161 /* this is responsible for setting those aspects of Region state
1162 that are mutable after construction.
1165 if ((prop = node.property ("name"))) {
1166 _name = prop->value();
1169 if ((prop = node.property ("type")) == 0) {
1170 _type = DataType::AUDIO;
1172 _type = DataType(prop->value());
1175 if ((prop = node.property ("start")) != 0) {
1176 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1177 if (val != _start) {
1178 what_changed = Change (what_changed|StartChanged);
1179 cerr << _name << " start changed\n";
1184 if ((prop = node.property ("length")) != 0) {
1185 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1186 if (val != _length) {
1187 what_changed = Change (what_changed|LengthChanged);
1188 cerr << _name << " length changed\n";
1189 _last_length = _length;
1194 if ((prop = node.property ("position")) != 0) {
1195 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1196 if (val != _position) {
1197 what_changed = Change (what_changed|PositionChanged);
1198 cerr << _name << " position changed\n";
1199 _last_position = _position;
1204 if ((prop = node.property ("layer")) != 0) {
1206 x = (layer_t) atoi (prop->value().c_str());
1208 what_changed = Change (what_changed|LayerChanged);
1209 cerr << _name << " layer changed\n";
1214 if ((prop = node.property ("sync-position")) != 0) {
1215 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1216 if (val != _sync_position) {
1217 what_changed = Change (what_changed|SyncOffsetChanged);
1218 cerr << _name << " sync changed\n";
1219 _sync_position = val;
1223 if ((prop = node.property ("positional-lock-style")) != 0) {
1224 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1226 if (_positional_lock_style == MusicTime) {
1227 if ((prop = node.property ("bbt-position")) == 0) {
1228 /* missing BBT info, revert to audio time locking */
1229 _positional_lock_style = AudioTime;
1231 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1234 &_bbt_time.ticks) != 3) {
1235 _positional_lock_style = AudioTime;
1242 /* XXX FIRST EDIT !!! */
1244 /* these 3 properties never change as a result of any editing */
1246 if ((prop = node.property ("ancestral-start")) != 0) {
1247 _ancestral_start = strtoll (prop->value().c_str(), 0, 10);
1249 _ancestral_start = _start;
1252 if ((prop = node.property ("ancestral-length")) != 0) {
1253 _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
1255 _ancestral_length = _length;
1258 if ((prop = node.property ("stretch")) != 0) {
1259 _stretch = atof (prop->value());
1261 /* fix problem with old sessions corrupted by an impossible
1264 if (_stretch == 0.0) {
1271 if ((prop = node.property ("shift")) != 0) {
1272 _shift = atof (prop->value());
1274 /* fix problem with old sessions corrupted by an impossible
1277 if (_shift == 0.0) {
1285 /* note: derived classes set flags */
1287 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1293 if (child->name () == "Extra") {
1295 _extra_xml = new XMLNode (*child);
1301 cerr << _name << ": final change to be sent: " << hex << what_changed << dec << endl;
1302 send_change (what_changed);
1309 Region::set_state (const XMLNode& node, int version)
1311 const XMLProperty *prop;
1312 Change what_changed = Change (0);
1314 /* ID is not allowed to change, ever */
1316 if ((prop = node.property ("id"))) {
1317 _id = prop->value();
1320 _first_edit = EditChangesNothing;
1322 set_live_state (node, version, what_changed, true);
1331 _last_length = _length;
1332 _last_position = _position;
1338 Change what_changed = Change (0);
1341 Glib::Mutex::Lock lm (_lock);
1343 if (_frozen && --_frozen > 0) {
1347 if (_pending_changed) {
1348 what_changed = _pending_changed;
1349 _pending_changed = Change (0);
1353 if (what_changed == Change (0)) {
1357 if (what_changed & LengthChanged) {
1358 if (what_changed & PositionChanged) {
1359 recompute_at_start ();
1361 recompute_at_end ();
1364 send_change (what_changed);
1368 Region::send_change (Change what_changed)
1372 Glib::Mutex::Lock lm (_lock);
1374 _pending_changed = Change (_pending_changed|what_changed);
1379 cerr << _name << " actually sends " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1380 StateChanged (what_changed);
1381 cerr << _name << " done with " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1383 if (!(_flags & DoNotSendPropertyChanges)) {
1385 /* Try and send a shared_pointer unless this is part of the constructor.
1390 boost::shared_ptr<Region> rptr = shared_from_this();
1391 cerr << _name << " actually sends prop change " << hex << what_changed << dec << " @ " << get_microseconds() << endl;
1392 RegionPropertyChanged (rptr);
1393 cerr << _name << " done with prop change @ " << get_microseconds() << endl;
1396 /* no shared_ptr available, relax; */
1403 Region::set_last_layer_op (uint64_t when)
1405 _last_layer_op = when;
1409 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1411 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1415 Region::equivalent (boost::shared_ptr<const Region> other) const
1417 return _start == other->_start &&
1418 _position == other->_position &&
1419 _length == other->_length;
1423 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1425 return _start == other->_start &&
1426 _length == other->_length;
1430 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1432 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1436 Region::source_deleted (boost::weak_ptr<Source>)
1440 if (!_session.deletion_in_progress()) {
1441 /* this is a very special case: at least one of the region's
1442 sources has bee deleted, so invalidate all references to
1443 ourselves. Do NOT do this during session deletion, because
1444 then we run the risk that this will actually result
1445 in this object being deleted (as refcnt goes to zero)
1446 while emitting DropReferences.
1454 Region::master_source_names ()
1456 SourceList::iterator i;
1458 vector<string> names;
1459 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1460 names.push_back((*i)->name());
1467 Region::set_master_sources (const SourceList& srcs)
1469 _master_sources = srcs;
1470 assert (_sources.size() == _master_sources.size());
1474 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1479 SourceList::const_iterator i;
1480 SourceList::const_iterator io;
1482 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1483 if ((*i)->id() != (*io)->id()) {
1488 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1489 if ((*i)->id() != (*io)->id()) {
1498 Region::uses_source (boost::shared_ptr<const Source> source) const
1500 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1509 Region::source_length(uint32_t n) const
1511 return _sources[n]->length(_position - _start);
1515 Region::verify_length (nframes_t len)
1517 if (source() && (source()->destructive() || source()->length_mutable())) {
1521 nframes_t maxlen = 0;
1523 for (uint32_t n=0; n < _sources.size(); ++n) {
1524 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1527 len = min (len, maxlen);
1533 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1535 if (source() && (source()->destructive() || source()->length_mutable())) {
1539 nframes_t maxlen = 0;
1541 for (uint32_t n=0; n < _sources.size(); ++n) {
1542 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1545 new_length = min (new_length, maxlen);
1551 Region::verify_start (nframes_t pos)
1553 if (source() && (source()->destructive() || source()->length_mutable())) {
1557 for (uint32_t n=0; n < _sources.size(); ++n) {
1558 if (pos > source_length(n) - _length) {
1566 Region::verify_start_mutable (nframes_t& new_start)
1568 if (source() && (source()->destructive() || source()->length_mutable())) {
1572 for (uint32_t n=0; n < _sources.size(); ++n) {
1573 if (new_start > source_length(n) - _length) {
1574 new_start = source_length(n) - _length;
1580 boost::shared_ptr<Region>
1581 Region::get_parent() const
1583 boost::shared_ptr<Playlist> pl (playlist());
1586 boost::shared_ptr<Region> r;
1587 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1589 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1590 return boost::static_pointer_cast<Region> (r);
1594 return boost::shared_ptr<Region>();
1598 Region::apply (Filter& filter)
1600 return filter.run (shared_from_this());
1605 Region::invalidate_transients ()
1607 _valid_transients = false;
1608 _transients.clear ();
1613 Region::use_sources (SourceList const & s)
1615 set<boost::shared_ptr<Source> > unique_srcs;
1617 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1618 _sources.push_back (*i);
1619 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1620 unique_srcs.insert (*i);
1623 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1624 _master_sources.push_back (*i);
1625 if (unique_srcs.find (*i) == unique_srcs.end()) {
1626 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));