2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
27 #include <sigc++/class_slot.h>
29 #include <glibmm/thread.h>
30 #include "pbd/xml++.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/enumwriter.h"
34 #include "ardour/region.h"
35 #include "ardour/playlist.h"
36 #include "ardour/session.h"
37 #include "ardour/source.h"
38 #include "ardour/tempo.h"
39 #include "ardour/region_factory.h"
40 #include "ardour/filter.h"
41 #include "ardour/profile.h"
42 #include "ardour/utils.h"
47 using namespace ARDOUR;
50 Change Region::FadeChanged = ARDOUR::new_change ();
51 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
52 Change Region::MuteChanged = ARDOUR::new_change ();
53 Change Region::OpacityChanged = ARDOUR::new_change ();
54 Change Region::LockChanged = ARDOUR::new_change ();
55 Change Region::LayerChanged = ARDOUR::new_change ();
56 Change Region::HiddenChanged = ARDOUR::new_change ();
58 sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
60 /* derived-from-derived constructor (no sources in constructor) */
61 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
62 : SessionObject(s, name)
69 , _positional_lock_style(AudioTime)
70 , _sync_position(_start)
72 , _first_edit(EditChangesNothing)
74 , _ancestral_start (0)
75 , _ancestral_length (0)
79 , _pending_changed(Change (0))
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)
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))
109 _sources.push_back (src);
110 _master_sources.push_back (src);
112 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), 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)
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))
141 assert(_sources.size() > 0);
144 /** Create a new Region from part of an existing one */
145 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
146 : SessionObject(other->session(), name)
147 , _type (other->data_type())
150 _start = other->_start + offset;
151 copy_stuff (other, offset, length, name, layer, flags);
153 /* if the other region had a distinct sync point
154 set, then continue to use it as best we can.
155 otherwise, reset sync point back to start.
158 if (other->flags() & SyncMarked) {
159 if (other->_sync_position < _start) {
160 _flags = Flag (_flags & ~SyncMarked);
161 _sync_position = _start;
163 _sync_position = other->_sync_position;
166 _flags = Flag (_flags & ~SyncMarked);
167 _sync_position = _start;
170 if (Profile->get_sae()) {
171 /* reset sync point to start if its ended up
172 outside region bounds.
175 if (_sync_position < _start || _sync_position >= _start + _length) {
176 _flags = Flag (_flags & ~SyncMarked);
177 _sync_position = _start;
182 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
183 : SessionObject(other->session(), name)
184 , _type (other->data_type())
186 /* create a new Region exactly like another but starting at 0 in its sources */
189 copy_stuff (other, 0, length, name, layer, flags);
191 /* sync pos is relative to start of file. our start-in-file is now zero,
192 so set our sync position to whatever the the difference between
193 _start and _sync_pos was in the other region.
195 result is that our new sync pos points to the same point in our source(s)
196 as the sync in the other region did in its source(s).
198 since we start at zero in our source(s), it is not possible to use a sync point that
199 is before the start. reset it to _start if that was true in the other region.
202 if (other->flags() & SyncMarked) {
203 if (other->_start < other->_sync_position) {
204 /* sync pos was after the start point of the other region */
205 _sync_position = other->_sync_position - other->_start;
207 /* sync pos was before the start point of the other region. not possible here. */
208 _flags = Flag (_flags & ~SyncMarked);
209 _sync_position = _start;
212 _flags = Flag (_flags & ~SyncMarked);
213 _sync_position = _start;
216 if (Profile->get_sae()) {
217 /* reset sync point to start if its ended up
218 outside region bounds.
221 if (_sync_position < _start || _sync_position >= _start + _length) {
222 _flags = Flag (_flags & ~SyncMarked);
223 _sync_position = _start;
227 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
229 _positional_lock_style = other->_positional_lock_style;
230 _first_edit = other->_first_edit;
233 /** Pure copy constructor */
234 Region::Region (boost::shared_ptr<const Region> other)
235 : SessionObject(other->session(), other->name())
236 , _type(other->data_type())
237 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
238 , _start(other->_start)
239 , _length(other->_length)
240 , _position(other->_position)
241 , _last_position(other->_last_position)
242 , _positional_lock_style(other->_positional_lock_style)
243 , _sync_position(other->_sync_position)
244 , _layer(other->_layer)
245 , _first_edit(EditChangesID)
247 , _ancestral_start (other->_ancestral_start)
248 , _ancestral_length (other->_ancestral_length)
249 , _stretch (other->_stretch)
250 , _shift (other->_shift)
251 , _valid_transients(false)
252 , _read_data_count(0)
253 , _pending_changed(Change(0))
254 , _last_layer_op(other->_last_layer_op)
256 other->_first_edit = EditChangesName;
258 if (other->_extra_xml) {
259 _extra_xml = new XMLNode (*other->_extra_xml);
264 use_sources (other->_sources);
265 assert(_sources.size() > 0);
268 Region::Region (const SourceList& srcs, const XMLNode& node)
269 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
270 , _type(DataType::NIL) // to be loaded from XML
276 , _positional_lock_style(AudioTime)
277 , _sync_position(_start)
279 , _first_edit(EditChangesNothing)
283 , _read_data_count(0)
284 , _pending_changed(Change(0))
287 set<boost::shared_ptr<Source> > unique_srcs;
289 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
290 _sources.push_back (*i);
291 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
292 unique_srcs.insert (*i);
295 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
296 _master_sources.push_back (*i);
297 if (unique_srcs.find (*i) == unique_srcs.end()) {
298 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
302 if (set_state (node)) {
303 throw failed_constructor();
306 assert(_type != DataType::NIL);
307 assert(_sources.size() > 0);
310 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
311 : SessionObject(src->session(), X_("error: XML did not reset this"))
312 , _type(DataType::NIL)
318 , _positional_lock_style(AudioTime)
319 , _sync_position(_start)
321 , _first_edit(EditChangesNothing)
325 , _read_data_count(0)
326 , _pending_changed(Change(0))
329 _sources.push_back (src);
331 if (set_state (node)) {
332 throw failed_constructor();
335 assert(_type != DataType::NIL);
336 assert(_sources.size() > 0);
341 boost::shared_ptr<Playlist> pl (playlist());
344 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
345 (*i)->remove_playlist (pl);
347 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
348 (*i)->remove_playlist (pl);
353 GoingAway (); /* EMIT SIGNAL */
357 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
360 _pending_changed = Change (0);
361 _read_data_count = 0;
362 _valid_transients = false;
365 _last_length = length;
366 _sync_position = other->_sync_position;
367 _ancestral_start = other->_ancestral_start;
368 _ancestral_length = other->_ancestral_length;
369 _stretch = other->_stretch;
370 _shift = other->_shift;
375 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
376 _first_edit = EditChangesNothing;
378 _positional_lock_style = AudioTime;
380 use_sources (other->_sources);
384 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
386 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
388 boost::shared_ptr<Playlist> pl (wpl.lock());
390 if (old_playlist == pl) {
398 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
399 (*i)->remove_playlist (_playlist);
400 (*i)->add_playlist (pl);
402 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
403 (*i)->remove_playlist (_playlist);
404 (*i)->add_playlist (pl);
407 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
408 (*i)->add_playlist (pl);
410 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
411 (*i)->add_playlist (pl);
416 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
417 (*i)->remove_playlist (old_playlist);
419 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
420 (*i)->remove_playlist (old_playlist);
427 Region::set_name (const std::string& str)
430 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
431 assert(_name == str);
432 send_change (ARDOUR::NameChanged);
439 Region::set_length (nframes_t len, void *src)
441 //cerr << "Region::set_length() len = " << len << endl;
442 if (_flags & Locked) {
446 if (_length != len && len != 0) {
448 /* check that the current _position wouldn't make the new
452 if (max_frames - len < _position) {
456 if (!verify_length (len)) {
461 _last_length = _length;
464 _flags = Region::Flag (_flags & ~WholeFile);
468 invalidate_transients ();
474 send_change (LengthChanged);
479 Region::maybe_uncopy ()
484 Region::first_edit ()
486 boost::shared_ptr<Playlist> pl (playlist());
488 if (_first_edit != EditChangesNothing && pl) {
490 _name = pl->session().new_region_name (_name);
491 _first_edit = EditChangesNothing;
493 send_change (ARDOUR::NameChanged);
494 RegionFactory::CheckNewRegion (shared_from_this());
499 Region::at_natural_position () const
501 boost::shared_ptr<Playlist> pl (playlist());
507 boost::shared_ptr<Region> whole_file_region = get_parent();
509 if (whole_file_region) {
510 if (_position == whole_file_region->position() + _start) {
519 Region::move_to_natural_position (void *src)
521 boost::shared_ptr<Playlist> pl (playlist());
527 boost::shared_ptr<Region> whole_file_region = get_parent();
529 if (whole_file_region) {
530 set_position (whole_file_region->position() + _start, src);
535 Region::special_set_position (nframes_t pos)
537 /* this is used when creating a whole file region as
538 a way to store its "natural" or "captured" position.
541 _position = _position;
546 Region::set_position_lock_style (PositionLockStyle ps)
548 boost::shared_ptr<Playlist> pl (playlist());
554 _positional_lock_style = ps;
556 if (_positional_lock_style == MusicTime) {
557 pl->session().tempo_map().bbt_time (_position, _bbt_time);
563 Region::update_position_after_tempo_map_change ()
565 boost::shared_ptr<Playlist> pl (playlist());
567 if (!pl || _positional_lock_style != MusicTime) {
571 TempoMap& map (pl->session().tempo_map());
572 nframes_t pos = map.frame_time (_bbt_time);
573 set_position_internal (pos, false);
577 Region::set_position (nframes_t pos, void *src)
583 set_position_internal (pos, true);
587 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
589 if (_position != pos) {
590 _last_position = _position;
593 /* check that the new _position wouldn't make the current
594 length impossible - if so, change the length.
596 XXX is this the right thing to do?
599 if (max_frames - _length < _position) {
600 _last_length = _length;
601 _length = max_frames - _position;
604 if (allow_bbt_recompute) {
605 recompute_position_from_lock_style ();
608 invalidate_transients ();
611 /* do this even if the position is the same. this helps out
612 a GUI that has moved its representation already.
615 send_change (PositionChanged);
619 Region::set_position_on_top (nframes_t pos, void *src)
621 if (_flags & Locked) {
625 if (_position != pos) {
626 _last_position = _position;
630 boost::shared_ptr<Playlist> pl (playlist());
633 pl->raise_region_to_top (shared_from_this ());
636 /* do this even if the position is the same. this helps out
637 a GUI that has moved its representation already.
640 send_change (PositionChanged);
644 Region::recompute_position_from_lock_style ()
646 if (_positional_lock_style == MusicTime) {
647 boost::shared_ptr<Playlist> pl (playlist());
649 pl->session().tempo_map().bbt_time (_position, _bbt_time);
655 Region::nudge_position (nframes64_t n, void *src)
657 if (_flags & Locked) {
665 _last_position = _position;
668 if (_position > max_frames - n) {
669 _position = max_frames;
674 if (_position < (nframes_t) -n) {
681 send_change (PositionChanged);
685 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
687 _ancestral_length = l;
688 _ancestral_start = s;
694 Region::set_start (nframes_t pos, void *src)
696 if (_flags & (Locked|PositionLocked)) {
699 /* This just sets the start, nothing else. It effectively shifts
700 the contents of the Region within the overall extent of the Source,
701 without changing the Region's position or length
706 if (!verify_start (pos)) {
711 _flags = Region::Flag (_flags & ~WholeFile);
713 invalidate_transients ();
715 send_change (StartChanged);
720 Region::trim_start (nframes_t new_position, void *src)
722 if (_flags & (Locked|PositionLocked)) {
728 if (new_position > _position) {
729 start_shift = new_position - _position;
731 start_shift = -(_position - new_position);
734 if (start_shift > 0) {
736 if (_start > max_frames - start_shift) {
737 new_start = max_frames;
739 new_start = _start + start_shift;
742 if (!verify_start (new_start)) {
746 } else if (start_shift < 0) {
748 if (_start < (nframes_t) -start_shift) {
751 new_start = _start + start_shift;
757 if (new_start == _start) {
762 _flags = Region::Flag (_flags & ~WholeFile);
765 send_change (StartChanged);
769 Region::trim_front (nframes_t new_position, void *src)
771 if (_flags & Locked) {
775 nframes_t end = last_frame();
776 nframes_t source_zero;
778 if (_position > _start) {
779 source_zero = _position - _start;
781 source_zero = 0; // its actually negative, but this will work for us
784 if (new_position < end) { /* can't trim it zero or negative length */
788 /* can't trim it back passed where source position zero is located */
790 new_position = max (new_position, source_zero);
793 if (new_position > _position) {
794 newlen = _length - (new_position - _position);
796 newlen = _length + (_position - new_position);
799 trim_to_internal (new_position, newlen, src);
801 recompute_at_start ();
807 Region::trim_end (nframes_t new_endpoint, void *src)
809 if (_flags & Locked) {
813 if (new_endpoint > _position) {
814 trim_to_internal (_position, new_endpoint - _position, this);
822 Region::trim_to (nframes_t position, nframes_t length, void *src)
824 if (_flags & Locked) {
828 trim_to_internal (position, length, src);
831 recompute_at_start ();
837 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
842 if (_flags & Locked) {
846 if (position > _position) {
847 start_shift = position - _position;
849 start_shift = -(_position - position);
852 if (start_shift > 0) {
854 if (_start > max_frames - start_shift) {
855 new_start = max_frames;
857 new_start = _start + start_shift;
861 } else if (start_shift < 0) {
863 if (_start < (nframes_t) -start_shift) {
866 new_start = _start + start_shift;
872 if (!verify_start_and_length (new_start, length)) {
876 Change what_changed = Change (0);
878 if (_start != new_start) {
880 what_changed = Change (what_changed|StartChanged);
882 if (_length != length) {
884 _last_length = _length;
887 what_changed = Change (what_changed|LengthChanged);
889 if (_position != position) {
891 _last_position = _position;
893 _position = position;
894 what_changed = Change (what_changed|PositionChanged);
897 _flags = Region::Flag (_flags & ~WholeFile);
899 if (what_changed & (StartChanged|LengthChanged)) {
904 send_change (what_changed);
909 Region::set_hidden (bool yn)
911 if (hidden() != yn) {
914 _flags = Flag (_flags|Hidden);
916 _flags = Flag (_flags & ~Hidden);
919 send_change (HiddenChanged);
924 Region::set_muted (bool yn)
929 _flags = Flag (_flags|Muted);
931 _flags = Flag (_flags & ~Muted);
934 send_change (MuteChanged);
939 Region::set_opaque (bool yn)
941 if (opaque() != yn) {
943 _flags = Flag (_flags|Opaque);
945 _flags = Flag (_flags & ~Opaque);
947 send_change (OpacityChanged);
952 Region::set_locked (bool yn)
954 if (locked() != yn) {
956 _flags = Flag (_flags|Locked);
958 _flags = Flag (_flags & ~Locked);
960 send_change (LockChanged);
965 Region::set_position_locked (bool yn)
967 if (position_locked() != yn) {
969 _flags = Flag (_flags|PositionLocked);
971 _flags = Flag (_flags & ~PositionLocked);
973 send_change (LockChanged);
978 Region::set_sync_position (nframes_t absolute_pos)
982 file_pos = _start + (absolute_pos - _position);
984 if (file_pos != _sync_position) {
986 _sync_position = file_pos;
987 _flags = Flag (_flags|SyncMarked);
992 send_change (SyncOffsetChanged);
997 Region::clear_sync_position ()
999 if (_flags & SyncMarked) {
1000 _flags = Flag (_flags & ~SyncMarked);
1005 send_change (SyncOffsetChanged);
1010 Region::sync_offset (int& dir) const
1012 /* returns the sync point relative the first frame of the region */
1014 if (_flags & SyncMarked) {
1015 if (_sync_position > _start) {
1017 return _sync_position - _start;
1020 return _start - _sync_position;
1029 Region::adjust_to_sync (nframes_t pos) const
1032 nframes_t offset = sync_offset (sync_dir);
1034 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1043 if (max_frames - pos > offset) {
1052 Region::sync_position() const
1054 if (_flags & SyncMarked) {
1055 return _sync_position;
1064 boost::shared_ptr<Playlist> pl (playlist());
1066 pl->raise_region (shared_from_this ());
1073 boost::shared_ptr<Playlist> pl (playlist());
1075 pl->lower_region (shared_from_this ());
1081 Region::raise_to_top ()
1083 boost::shared_ptr<Playlist> pl (playlist());
1085 pl->raise_region_to_top (shared_from_this());
1090 Region::lower_to_bottom ()
1092 boost::shared_ptr<Playlist> pl (playlist());
1094 pl->lower_region_to_bottom (shared_from_this());
1099 Region::set_layer (layer_t l)
1104 send_change (LayerChanged);
1109 Region::state (bool full_state)
1111 XMLNode *node = new XMLNode ("Region");
1113 const char* fe = NULL;
1115 _id.print (buf, sizeof (buf));
1116 node->add_property ("id", buf);
1117 node->add_property ("name", _name);
1118 node->add_property ("type", _type.to_string());
1119 snprintf (buf, sizeof (buf), "%u", _start);
1120 node->add_property ("start", buf);
1121 snprintf (buf, sizeof (buf), "%u", _length);
1122 node->add_property ("length", buf);
1123 snprintf (buf, sizeof (buf), "%u", _position);
1124 node->add_property ("position", buf);
1125 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1126 node->add_property ("ancestral-start", buf);
1127 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1128 node->add_property ("ancestral-length", buf);
1129 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1130 node->add_property ("stretch", buf);
1131 snprintf (buf, sizeof (buf), "%.12g", _shift);
1132 node->add_property ("shift", buf);
1134 switch (_first_edit) {
1135 case EditChangesNothing:
1138 case EditChangesName:
1144 default: /* should be unreachable but makes g++ happy */
1149 node->add_property ("first-edit", fe);
1151 /* note: flags are stored by derived classes */
1153 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1154 node->add_property ("layer", buf);
1155 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1156 node->add_property ("sync-position", buf);
1158 if (_positional_lock_style != AudioTime) {
1159 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1162 node->add_property ("bbt-position", str.str());
1169 Region::get_state ()
1171 return state (true);
1175 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1177 const XMLNodeList& nlist = node.children();
1178 const XMLProperty *prop;
1181 /* this is responsible for setting those aspects of Region state
1182 that are mutable after construction.
1185 if ((prop = node.property ("name")) == 0) {
1186 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1190 _name = prop->value();
1192 if ((prop = node.property ("type")) == 0) {
1193 _type = DataType::AUDIO;
1195 _type = DataType(prop->value());
1198 if ((prop = node.property ("start")) != 0) {
1199 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1200 if (val != _start) {
1201 what_changed = Change (what_changed|StartChanged);
1208 if ((prop = node.property ("length")) != 0) {
1209 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1210 if (val != _length) {
1211 what_changed = Change (what_changed|LengthChanged);
1212 _last_length = _length;
1216 _last_length = _length;
1220 if ((prop = node.property ("position")) != 0) {
1221 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1222 if (val != _position) {
1223 what_changed = Change (what_changed|PositionChanged);
1224 _last_position = _position;
1228 _last_position = _position;
1232 if ((prop = node.property ("layer")) != 0) {
1234 x = (layer_t) atoi (prop->value().c_str());
1236 what_changed = Change (what_changed|LayerChanged);
1243 if ((prop = node.property ("sync-position")) != 0) {
1244 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1245 if (val != _sync_position) {
1246 what_changed = Change (what_changed|SyncOffsetChanged);
1247 _sync_position = val;
1250 _sync_position = _start;
1253 if ((prop = node.property ("positional-lock-style")) != 0) {
1254 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1256 if (_positional_lock_style == MusicTime) {
1257 if ((prop = node.property ("bbt-position")) == 0) {
1258 /* missing BBT info, revert to audio time locking */
1259 _positional_lock_style = AudioTime;
1261 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1264 &_bbt_time.ticks) != 3) {
1265 _positional_lock_style = AudioTime;
1271 _positional_lock_style = AudioTime;
1274 /* XXX FIRST EDIT !!! */
1276 /* these 3 properties never change as a result of any editing */
1278 if ((prop = node.property ("ancestral-start")) != 0) {
1279 _ancestral_start = strtoll (prop->value().c_str(), 0, 10);
1281 _ancestral_start = _start;
1284 if ((prop = node.property ("ancestral-length")) != 0) {
1285 _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
1287 _ancestral_length = _length;
1290 if ((prop = node.property ("stretch")) != 0) {
1291 _stretch = atof (prop->value());
1293 /* fix problem with old sessions corrupted by an impossible
1296 if (_stretch == 0.0) {
1303 if ((prop = node.property ("shift")) != 0) {
1304 _shift = atof (prop->value());
1306 /* fix problem with old sessions corrupted by an impossible
1309 if (_shift == 0.0) {
1317 /* note: derived classes set flags */
1322 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1328 if (child->name () == "Extra") {
1329 _extra_xml = new XMLNode (*child);
1335 send_change (what_changed);
1342 Region::set_state (const XMLNode& node)
1344 const XMLProperty *prop;
1345 Change what_changed = Change (0);
1347 /* ID is not allowed to change, ever */
1349 if ((prop = node.property ("id")) == 0) {
1350 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1354 _id = prop->value();
1356 _first_edit = EditChangesNothing;
1358 set_live_state (node, what_changed, true);
1367 _last_length = _length;
1368 _last_position = _position;
1372 Region::thaw (const string& why)
1374 Change what_changed = Change (0);
1377 Glib::Mutex::Lock lm (_lock);
1379 if (_frozen && --_frozen > 0) {
1383 if (_pending_changed) {
1384 what_changed = _pending_changed;
1385 _pending_changed = Change (0);
1389 if (what_changed == Change (0)) {
1393 if (what_changed & LengthChanged) {
1394 if (what_changed & PositionChanged) {
1395 recompute_at_start ();
1397 recompute_at_end ();
1400 StateChanged (what_changed);
1404 Region::send_change (Change what_changed)
1407 Glib::Mutex::Lock lm (_lock);
1409 _pending_changed = Change (_pending_changed|what_changed);
1414 StateChanged (what_changed);
1416 if (!(_flags & DoNotSaveState)) {
1418 /* Try and send a shared_pointer unless this is part of the constructor.
1423 boost::shared_ptr<Region> rptr = shared_from_this();
1424 RegionPropertyChanged (rptr);
1426 /* no shared_ptr available, relax; */
1433 Region::set_last_layer_op (uint64_t when)
1435 _last_layer_op = when;
1439 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1441 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1445 Region::equivalent (boost::shared_ptr<const Region> other) const
1447 return _start == other->_start &&
1448 _position == other->_position &&
1449 _length == other->_length;
1453 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1455 return _start == other->_start &&
1456 _length == other->_length;
1460 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1462 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1466 Region::source_deleted (boost::shared_ptr<Source>)
1473 Region::master_source_names ()
1475 SourceList::iterator i;
1477 vector<string> names;
1478 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1479 names.push_back((*i)->name());
1486 Region::set_master_sources (const SourceList& srcs)
1488 _master_sources = srcs;
1492 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1497 SourceList::const_iterator i;
1498 SourceList::const_iterator io;
1500 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1501 if ((*i)->id() != (*io)->id()) {
1506 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1507 if ((*i)->id() != (*io)->id()) {
1516 Region::source_length(uint32_t n) const
1518 return _sources[n]->length(_position - _start);
1522 Region::verify_length (nframes_t len)
1524 if (source() && (source()->destructive() || source()->length_mutable())) {
1528 nframes_t maxlen = 0;
1530 for (uint32_t n=0; n < _sources.size(); ++n) {
1531 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1534 len = min (len, maxlen);
1540 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1542 if (source() && (source()->destructive() || source()->length_mutable())) {
1546 nframes_t maxlen = 0;
1548 for (uint32_t n=0; n < _sources.size(); ++n) {
1549 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1552 new_length = min (new_length, maxlen);
1558 Region::verify_start (nframes_t pos)
1560 if (source() && (source()->destructive() || source()->length_mutable())) {
1564 for (uint32_t n=0; n < _sources.size(); ++n) {
1565 if (pos > source_length(n) - _length) {
1573 Region::verify_start_mutable (nframes_t& new_start)
1575 if (source() && (source()->destructive() || source()->length_mutable())) {
1579 for (uint32_t n=0; n < _sources.size(); ++n) {
1580 if (new_start > source_length(n) - _length) {
1581 new_start = source_length(n) - _length;
1587 boost::shared_ptr<Region>
1588 Region::get_parent() const
1590 boost::shared_ptr<Playlist> pl (playlist());
1593 boost::shared_ptr<Region> r;
1594 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1596 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1597 return boost::static_pointer_cast<Region> (r);
1601 return boost::shared_ptr<Region>();
1605 Region::apply (Filter& filter)
1607 return filter.run (shared_from_this());
1612 Region::invalidate_transients ()
1614 _valid_transients = false;
1615 _transients.clear ();
1620 Region::use_sources (SourceList const & s)
1622 set<boost::shared_ptr<Source> > unique_srcs;
1624 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1625 _sources.push_back (*i);
1626 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));
1627 unique_srcs.insert (*i);
1630 for (SourceList::const_iterator i = s.begin(); i != s.end(); ++i) {
1631 _master_sources.push_back (*i);
1632 if (unique_srcs.find (*i) == unique_srcs.end()) {
1633 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));