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)
77 , _pending_changed(Change (0))
80 /* no sources at this point */
83 /** Basic Region constructor (single source) */
84 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
85 : SessionObject(src->session(), name)
92 , _positional_lock_style(AudioTime)
93 , _sync_position(_start)
95 , _first_edit(EditChangesNothing)
97 , _ancestral_start (0)
98 , _ancestral_length (0)
101 , _valid_transients(false)
102 , _read_data_count(0)
103 , _pending_changed(Change (0))
107 _sources.push_back (src);
108 _master_sources.push_back (src);
110 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
112 assert(_sources.size() > 0);
113 _positional_lock_style = AudioTime;
116 /** Basic Region constructor (many sources) */
117 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
118 : SessionObject(srcs.front()->session(), name)
125 , _positional_lock_style(AudioTime)
126 , _sync_position(_start)
128 , _first_edit(EditChangesNothing)
132 , _read_data_count(0)
133 , _pending_changed(Change (0))
137 set<boost::shared_ptr<Source> > unique_srcs;
139 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
140 _sources.push_back (*i);
141 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
142 unique_srcs.insert (*i);
145 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
146 _master_sources.push_back (*i);
147 if (unique_srcs.find (*i) == unique_srcs.end()) {
148 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
152 assert(_sources.size() > 0);
155 /** Create a new Region from part of an existing one */
156 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
157 : SessionObject(other->session(), name)
158 , _type (other->data_type())
161 _start = other->_start + offset;
162 copy_stuff (other, offset, length, name, layer, flags);
164 /* if the other region had a distinct sync point
165 set, then continue to use it as best we can.
166 otherwise, reset sync point back to start.
169 if (other->flags() & SyncMarked) {
170 if (other->_sync_position < _start) {
171 _flags = Flag (_flags & ~SyncMarked);
172 _sync_position = _start;
174 _sync_position = other->_sync_position;
177 _flags = Flag (_flags & ~SyncMarked);
178 _sync_position = _start;
181 if (Profile->get_sae()) {
182 /* reset sync point to start if its ended up
183 outside region bounds.
186 if (_sync_position < _start || _sync_position >= _start + _length) {
187 _flags = Flag (_flags & ~SyncMarked);
188 _sync_position = _start;
193 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
194 : SessionObject(other->session(), name)
195 , _type (other->data_type())
197 /* create a new Region exactly like another but starting at 0 in its sources */
200 copy_stuff (other, 0, length, name, layer, flags);
202 /* sync pos is relative to start of file. our start-in-file is now zero,
203 so set our sync position to whatever the the difference between
204 _start and _sync_pos was in the other region.
206 result is that our new sync pos points to the same point in our source(s)
207 as the sync in the other region did in its source(s).
209 since we start at zero in our source(s), it is not possible to use a sync point that
210 is before the start. reset it to _start if that was true in the other region.
213 if (other->flags() & SyncMarked) {
214 if (other->_start < other->_sync_position) {
215 /* sync pos was after the start point of the other region */
216 _sync_position = other->_sync_position - other->_start;
218 /* sync pos was before the start point of the other region. not possible here. */
219 _flags = Flag (_flags & ~SyncMarked);
220 _sync_position = _start;
223 _flags = Flag (_flags & ~SyncMarked);
224 _sync_position = _start;
227 if (Profile->get_sae()) {
228 /* reset sync point to start if its ended up
229 outside region bounds.
232 if (_sync_position < _start || _sync_position >= _start + _length) {
233 _flags = Flag (_flags & ~SyncMarked);
234 _sync_position = _start;
238 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
240 _positional_lock_style = other->_positional_lock_style;
241 _first_edit = other->_first_edit;
244 /** Pure copy constructor */
245 Region::Region (boost::shared_ptr<const Region> other)
246 : SessionObject(other->session(), other->name())
247 , _type(other->data_type())
248 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
249 , _start(other->_start)
250 , _length(other->_length)
251 , _position(other->_position)
252 , _last_position(other->_last_position)
253 , _positional_lock_style(other->_positional_lock_style)
254 , _sync_position(other->_sync_position)
255 , _layer(other->_layer)
256 , _first_edit(EditChangesID)
258 , _ancestral_start (other->_ancestral_start)
259 , _ancestral_length (other->_ancestral_length)
260 , _stretch (other->_stretch)
261 , _shift (other->_shift)
262 , _valid_transients(false)
263 , _read_data_count(0)
264 , _pending_changed(Change(0))
265 , _last_layer_op(other->_last_layer_op)
267 other->_first_edit = EditChangesName;
269 if (other->_extra_xml) {
270 _extra_xml = new XMLNode (*other->_extra_xml);
275 set<boost::shared_ptr<Source> > unique_srcs;
277 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
278 _sources.push_back (*i);
279 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
280 unique_srcs.insert (*i);
283 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
284 _master_sources.push_back (*i);
285 if (unique_srcs.find (*i) == unique_srcs.end()) {
286 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
290 assert(_sources.size() > 0);
293 Region::Region (const SourceList& srcs, const XMLNode& node)
294 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
295 , _type(DataType::NIL) // to be loaded from XML
301 , _positional_lock_style(AudioTime)
302 , _sync_position(_start)
304 , _first_edit(EditChangesNothing)
308 , _read_data_count(0)
309 , _pending_changed(Change(0))
312 set<boost::shared_ptr<Source> > unique_srcs;
314 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
315 _sources.push_back (*i);
316 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
317 unique_srcs.insert (*i);
320 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
321 _master_sources.push_back (*i);
322 if (unique_srcs.find (*i) == unique_srcs.end()) {
323 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
327 if (set_state (node)) {
328 throw failed_constructor();
331 assert(_type != DataType::NIL);
332 assert(_sources.size() > 0);
335 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
336 : SessionObject(src->session(), X_("error: XML did not reset this"))
337 , _type(DataType::NIL)
343 , _positional_lock_style(AudioTime)
344 , _sync_position(_start)
346 , _first_edit(EditChangesNothing)
350 , _read_data_count(0)
351 , _pending_changed(Change(0))
354 _sources.push_back (src);
356 if (set_state (node)) {
357 throw failed_constructor();
360 assert(_type != DataType::NIL);
361 assert(_sources.size() > 0);
366 boost::shared_ptr<Playlist> pl (playlist());
369 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
370 (*i)->remove_playlist (pl);
372 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
373 (*i)->remove_playlist (pl);
378 GoingAway (); /* EMIT SIGNAL */
382 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
385 _pending_changed = Change (0);
386 _read_data_count = 0;
387 _valid_transients = false;
390 _last_length = length;
391 _sync_position = other->_sync_position;
392 _ancestral_start = other->_ancestral_start;
393 _ancestral_length = other->_ancestral_length;
394 _stretch = other->_stretch;
395 _shift = other->_shift;
400 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
401 _first_edit = EditChangesNothing;
403 _positional_lock_style = AudioTime;
407 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
409 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
411 boost::shared_ptr<Playlist> pl (wpl.lock());
413 if (old_playlist == pl) {
421 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
422 (*i)->remove_playlist (_playlist);
423 (*i)->add_playlist (pl);
425 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
426 (*i)->remove_playlist (_playlist);
427 (*i)->add_playlist (pl);
430 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
431 (*i)->add_playlist (pl);
433 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
434 (*i)->add_playlist (pl);
439 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
440 (*i)->remove_playlist (old_playlist);
442 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
443 (*i)->remove_playlist (old_playlist);
450 Region::set_name (const std::string& str)
453 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
454 assert(_name == str);
455 send_change (ARDOUR::NameChanged);
462 Region::set_length (nframes_t len, void *src)
464 //cerr << "Region::set_length() len = " << len << endl;
465 if (_flags & Locked) {
469 if (_length != len && len != 0) {
471 /* check that the current _position wouldn't make the new
475 if (max_frames - len < _position) {
479 if (!verify_length (len)) {
484 _last_length = _length;
487 _flags = Region::Flag (_flags & ~WholeFile);
491 invalidate_transients ();
497 send_change (LengthChanged);
502 Region::maybe_uncopy ()
507 Region::first_edit ()
509 boost::shared_ptr<Playlist> pl (playlist());
511 if (_first_edit != EditChangesNothing && pl) {
513 _name = pl->session().new_region_name (_name);
514 _first_edit = EditChangesNothing;
516 send_change (ARDOUR::NameChanged);
517 RegionFactory::CheckNewRegion (shared_from_this());
522 Region::at_natural_position () const
524 boost::shared_ptr<Playlist> pl (playlist());
530 boost::shared_ptr<Region> whole_file_region = get_parent();
532 if (whole_file_region) {
533 if (_position == whole_file_region->position() + _start) {
542 Region::move_to_natural_position (void *src)
544 boost::shared_ptr<Playlist> pl (playlist());
550 boost::shared_ptr<Region> whole_file_region = get_parent();
552 if (whole_file_region) {
553 set_position (whole_file_region->position() + _start, src);
558 Region::special_set_position (nframes_t pos)
560 /* this is used when creating a whole file region as
561 a way to store its "natural" or "captured" position.
564 _position = _position;
569 Region::set_position_lock_style (PositionLockStyle ps)
571 boost::shared_ptr<Playlist> pl (playlist());
577 _positional_lock_style = ps;
579 if (_positional_lock_style == MusicTime) {
580 pl->session().tempo_map().bbt_time (_position, _bbt_time);
586 Region::update_position_after_tempo_map_change ()
588 boost::shared_ptr<Playlist> pl (playlist());
590 if (!pl || _positional_lock_style != MusicTime) {
594 TempoMap& map (pl->session().tempo_map());
595 nframes_t pos = map.frame_time (_bbt_time);
596 set_position_internal (pos, false);
600 Region::set_position (nframes_t pos, void *src)
606 set_position_internal (pos, true);
610 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
612 if (_position != pos) {
613 _last_position = _position;
616 /* check that the new _position wouldn't make the current
617 length impossible - if so, change the length.
619 XXX is this the right thing to do?
622 if (max_frames - _length < _position) {
623 _last_length = _length;
624 _length = max_frames - _position;
627 if (allow_bbt_recompute) {
628 recompute_position_from_lock_style ();
631 invalidate_transients ();
634 /* do this even if the position is the same. this helps out
635 a GUI that has moved its representation already.
638 send_change (PositionChanged);
642 Region::set_position_on_top (nframes_t pos, void *src)
644 if (_flags & Locked) {
648 if (_position != pos) {
649 _last_position = _position;
653 boost::shared_ptr<Playlist> pl (playlist());
656 pl->raise_region_to_top (shared_from_this ());
659 /* do this even if the position is the same. this helps out
660 a GUI that has moved its representation already.
663 send_change (PositionChanged);
667 Region::recompute_position_from_lock_style ()
669 if (_positional_lock_style == MusicTime) {
670 boost::shared_ptr<Playlist> pl (playlist());
672 pl->session().tempo_map().bbt_time (_position, _bbt_time);
678 Region::nudge_position (nframes64_t n, void *src)
680 if (_flags & Locked) {
688 _last_position = _position;
691 if (_position > max_frames - n) {
692 _position = max_frames;
697 if (_position < (nframes_t) -n) {
704 send_change (PositionChanged);
708 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
710 _ancestral_length = l;
711 _ancestral_start = s;
717 Region::set_start (nframes_t pos, void *src)
719 if (_flags & (Locked|PositionLocked)) {
722 /* This just sets the start, nothing else. It effectively shifts
723 the contents of the Region within the overall extent of the Source,
724 without changing the Region's position or length
729 if (!verify_start (pos)) {
734 _flags = Region::Flag (_flags & ~WholeFile);
736 invalidate_transients ();
738 send_change (StartChanged);
743 Region::trim_start (nframes_t new_position, void *src)
745 if (_flags & (Locked|PositionLocked)) {
751 if (new_position > _position) {
752 start_shift = new_position - _position;
754 start_shift = -(_position - new_position);
757 if (start_shift > 0) {
759 if (_start > max_frames - start_shift) {
760 new_start = max_frames;
762 new_start = _start + start_shift;
765 if (!verify_start (new_start)) {
769 } else if (start_shift < 0) {
771 if (_start < (nframes_t) -start_shift) {
774 new_start = _start + start_shift;
780 if (new_start == _start) {
785 _flags = Region::Flag (_flags & ~WholeFile);
788 send_change (StartChanged);
792 Region::trim_front (nframes_t new_position, void *src)
794 if (_flags & Locked) {
798 nframes_t end = last_frame();
799 nframes_t source_zero;
801 if (_position > _start) {
802 source_zero = _position - _start;
804 source_zero = 0; // its actually negative, but this will work for us
807 if (new_position < end) { /* can't trim it zero or negative length */
811 /* can't trim it back passed where source position zero is located */
813 new_position = max (new_position, source_zero);
816 if (new_position > _position) {
817 newlen = _length - (new_position - _position);
819 newlen = _length + (_position - new_position);
822 trim_to_internal (new_position, newlen, src);
824 recompute_at_start ();
830 Region::trim_end (nframes_t new_endpoint, void *src)
832 if (_flags & Locked) {
836 if (new_endpoint > _position) {
837 trim_to_internal (_position, new_endpoint - _position, this);
845 Region::trim_to (nframes_t position, nframes_t length, void *src)
847 if (_flags & Locked) {
851 trim_to_internal (position, length, src);
854 recompute_at_start ();
860 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
865 if (_flags & Locked) {
869 if (position > _position) {
870 start_shift = position - _position;
872 start_shift = -(_position - position);
875 if (start_shift > 0) {
877 if (_start > max_frames - start_shift) {
878 new_start = max_frames;
880 new_start = _start + start_shift;
884 } else if (start_shift < 0) {
886 if (_start < (nframes_t) -start_shift) {
889 new_start = _start + start_shift;
895 if (!verify_start_and_length (new_start, length)) {
899 Change what_changed = Change (0);
901 if (_start != new_start) {
903 what_changed = Change (what_changed|StartChanged);
905 if (_length != length) {
907 _last_length = _length;
910 what_changed = Change (what_changed|LengthChanged);
912 if (_position != position) {
914 _last_position = _position;
916 _position = position;
917 what_changed = Change (what_changed|PositionChanged);
920 _flags = Region::Flag (_flags & ~WholeFile);
922 if (what_changed & (StartChanged|LengthChanged)) {
927 send_change (what_changed);
932 Region::set_hidden (bool yn)
934 if (hidden() != yn) {
937 _flags = Flag (_flags|Hidden);
939 _flags = Flag (_flags & ~Hidden);
942 send_change (HiddenChanged);
947 Region::set_muted (bool yn)
952 _flags = Flag (_flags|Muted);
954 _flags = Flag (_flags & ~Muted);
957 send_change (MuteChanged);
962 Region::set_opaque (bool yn)
964 if (opaque() != yn) {
966 _flags = Flag (_flags|Opaque);
968 _flags = Flag (_flags & ~Opaque);
970 send_change (OpacityChanged);
975 Region::set_locked (bool yn)
977 if (locked() != yn) {
979 _flags = Flag (_flags|Locked);
981 _flags = Flag (_flags & ~Locked);
983 send_change (LockChanged);
988 Region::set_position_locked (bool yn)
990 if (position_locked() != yn) {
992 _flags = Flag (_flags|PositionLocked);
994 _flags = Flag (_flags & ~PositionLocked);
996 send_change (LockChanged);
1001 Region::set_sync_position (nframes_t absolute_pos)
1005 file_pos = _start + (absolute_pos - _position);
1007 if (file_pos != _sync_position) {
1009 _sync_position = file_pos;
1010 _flags = Flag (_flags|SyncMarked);
1015 send_change (SyncOffsetChanged);
1020 Region::clear_sync_position ()
1022 if (_flags & SyncMarked) {
1023 _flags = Flag (_flags & ~SyncMarked);
1028 send_change (SyncOffsetChanged);
1033 Region::sync_offset (int& dir) const
1035 /* returns the sync point relative the first frame of the region */
1037 if (_flags & SyncMarked) {
1038 if (_sync_position > _start) {
1040 return _sync_position - _start;
1043 return _start - _sync_position;
1052 Region::adjust_to_sync (nframes_t pos) const
1055 nframes_t offset = sync_offset (sync_dir);
1057 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1066 if (max_frames - pos > offset) {
1075 Region::sync_position() const
1077 if (_flags & SyncMarked) {
1078 return _sync_position;
1087 boost::shared_ptr<Playlist> pl (playlist());
1089 pl->raise_region (shared_from_this ());
1096 boost::shared_ptr<Playlist> pl (playlist());
1098 pl->lower_region (shared_from_this ());
1104 Region::raise_to_top ()
1106 boost::shared_ptr<Playlist> pl (playlist());
1108 pl->raise_region_to_top (shared_from_this());
1113 Region::lower_to_bottom ()
1115 boost::shared_ptr<Playlist> pl (playlist());
1117 pl->lower_region_to_bottom (shared_from_this());
1122 Region::set_layer (layer_t l)
1127 send_change (LayerChanged);
1132 Region::state (bool full_state)
1134 XMLNode *node = new XMLNode ("Region");
1136 const char* fe = NULL;
1138 _id.print (buf, sizeof (buf));
1139 node->add_property ("id", buf);
1140 node->add_property ("name", _name);
1141 node->add_property ("type", _type.to_string());
1142 snprintf (buf, sizeof (buf), "%u", _start);
1143 node->add_property ("start", buf);
1144 snprintf (buf, sizeof (buf), "%u", _length);
1145 node->add_property ("length", buf);
1146 snprintf (buf, sizeof (buf), "%u", _position);
1147 node->add_property ("position", buf);
1148 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1149 node->add_property ("ancestral-start", buf);
1150 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1151 node->add_property ("ancestral-length", buf);
1152 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1153 node->add_property ("stretch", buf);
1154 snprintf (buf, sizeof (buf), "%.12g", _shift);
1155 node->add_property ("shift", buf);
1157 switch (_first_edit) {
1158 case EditChangesNothing:
1161 case EditChangesName:
1167 default: /* should be unreachable but makes g++ happy */
1172 node->add_property ("first-edit", fe);
1174 /* note: flags are stored by derived classes */
1176 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1177 node->add_property ("layer", buf);
1178 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1179 node->add_property ("sync-position", buf);
1181 if (_positional_lock_style != AudioTime) {
1182 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1185 node->add_property ("bbt-position", str.str());
1192 Region::get_state ()
1194 return state (true);
1198 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1200 const XMLNodeList& nlist = node.children();
1201 const XMLProperty *prop;
1204 /* this is responsible for setting those aspects of Region state
1205 that are mutable after construction.
1208 if ((prop = node.property ("name")) == 0) {
1209 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1213 _name = prop->value();
1215 if ((prop = node.property ("type")) == 0) {
1216 _type = DataType::AUDIO;
1218 _type = DataType(prop->value());
1221 if ((prop = node.property ("start")) != 0) {
1222 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1223 if (val != _start) {
1224 what_changed = Change (what_changed|StartChanged);
1231 if ((prop = node.property ("length")) != 0) {
1232 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1233 if (val != _length) {
1234 what_changed = Change (what_changed|LengthChanged);
1235 _last_length = _length;
1239 _last_length = _length;
1243 if ((prop = node.property ("position")) != 0) {
1244 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1245 if (val != _position) {
1246 what_changed = Change (what_changed|PositionChanged);
1247 _last_position = _position;
1251 _last_position = _position;
1255 if ((prop = node.property ("layer")) != 0) {
1257 x = (layer_t) atoi (prop->value().c_str());
1259 what_changed = Change (what_changed|LayerChanged);
1266 if ((prop = node.property ("sync-position")) != 0) {
1267 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1268 if (val != _sync_position) {
1269 what_changed = Change (what_changed|SyncOffsetChanged);
1270 _sync_position = val;
1273 _sync_position = _start;
1276 if ((prop = node.property ("positional-lock-style")) != 0) {
1277 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1279 if (_positional_lock_style == MusicTime) {
1280 if ((prop = node.property ("bbt-position")) == 0) {
1281 /* missing BBT info, revert to audio time locking */
1282 _positional_lock_style = AudioTime;
1284 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1287 &_bbt_time.ticks) != 3) {
1288 _positional_lock_style = AudioTime;
1294 _positional_lock_style = AudioTime;
1297 /* XXX FIRST EDIT !!! */
1299 /* these 3 properties never change as a result of any editing */
1301 if ((prop = node.property ("ancestral-start")) != 0) {
1302 _ancestral_start = atoi (prop->value());
1304 _ancestral_start = _start;
1307 if ((prop = node.property ("ancestral-length")) != 0) {
1308 _ancestral_length = atoi (prop->value());
1310 _ancestral_length = _length;
1313 if ((prop = node.property ("stretch")) != 0) {
1314 _stretch = atof (prop->value());
1316 /* fix problem with old sessions corrupted by an impossible
1319 if (_stretch == 0.0) {
1326 if ((prop = node.property ("shift")) != 0) {
1327 _shift = atof (prop->value());
1329 /* fix problem with old sessions corrupted by an impossible
1332 if (_shift == 0.0) {
1340 /* note: derived classes set flags */
1345 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1351 if (child->name () == "Extra") {
1352 _extra_xml = new XMLNode (*child);
1358 send_change (what_changed);
1365 Region::set_state (const XMLNode& node)
1367 const XMLProperty *prop;
1368 Change what_changed = Change (0);
1370 /* ID is not allowed to change, ever */
1372 if ((prop = node.property ("id")) == 0) {
1373 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1377 _id = prop->value();
1379 _first_edit = EditChangesNothing;
1381 set_live_state (node, what_changed, true);
1390 _last_length = _length;
1391 _last_position = _position;
1395 Region::thaw (const string& why)
1397 Change what_changed = Change (0);
1400 Glib::Mutex::Lock lm (_lock);
1402 if (_frozen && --_frozen > 0) {
1406 if (_pending_changed) {
1407 what_changed = _pending_changed;
1408 _pending_changed = Change (0);
1412 if (what_changed == Change (0)) {
1416 if (what_changed & LengthChanged) {
1417 if (what_changed & PositionChanged) {
1418 recompute_at_start ();
1420 recompute_at_end ();
1423 StateChanged (what_changed);
1427 Region::send_change (Change what_changed)
1430 Glib::Mutex::Lock lm (_lock);
1432 _pending_changed = Change (_pending_changed|what_changed);
1437 StateChanged (what_changed);
1439 if (!(_flags & DoNotSaveState)) {
1441 /* Try and send a shared_pointer unless this is part of the constructor.
1446 boost::shared_ptr<Region> rptr = shared_from_this();
1447 RegionPropertyChanged (rptr);
1449 /* no shared_ptr available, relax; */
1456 Region::set_last_layer_op (uint64_t when)
1458 _last_layer_op = when;
1462 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1464 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1468 Region::equivalent (boost::shared_ptr<const Region> other) const
1470 return _start == other->_start &&
1471 _position == other->_position &&
1472 _length == other->_length;
1476 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1478 return _start == other->_start &&
1479 _length == other->_length;
1483 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1485 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1489 Region::source_deleted (boost::shared_ptr<Source>)
1496 Region::master_source_names ()
1498 SourceList::iterator i;
1500 vector<string> names;
1501 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1502 names.push_back((*i)->name());
1509 Region::set_master_sources (const SourceList& srcs)
1511 _master_sources = srcs;
1515 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1520 SourceList::const_iterator i;
1521 SourceList::const_iterator io;
1523 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1524 if ((*i)->id() != (*io)->id()) {
1529 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1530 if ((*i)->id() != (*io)->id()) {
1539 Region::source_length(uint32_t n) const
1541 return _sources[n]->length(_position - _start);
1545 Region::verify_length (nframes_t len)
1547 if (source() && (source()->destructive() || source()->length_mutable())) {
1551 nframes_t maxlen = 0;
1553 for (uint32_t n=0; n < _sources.size(); ++n) {
1554 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1557 len = min (len, maxlen);
1563 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1565 if (source() && (source()->destructive() || source()->length_mutable())) {
1569 nframes_t maxlen = 0;
1571 for (uint32_t n=0; n < _sources.size(); ++n) {
1572 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1575 new_length = min (new_length, maxlen);
1581 Region::verify_start (nframes_t pos)
1583 if (source() && (source()->destructive() || source()->length_mutable())) {
1587 for (uint32_t n=0; n < _sources.size(); ++n) {
1588 if (pos > source_length(n) - _length) {
1596 Region::verify_start_mutable (nframes_t& new_start)
1598 if (source() && (source()->destructive() || source()->length_mutable())) {
1602 for (uint32_t n=0; n < _sources.size(); ++n) {
1603 if (new_start > source_length(n) - _length) {
1604 new_start = source_length(n) - _length;
1610 boost::shared_ptr<Region>
1611 Region::get_parent() const
1613 boost::shared_ptr<Playlist> pl (playlist());
1616 boost::shared_ptr<Region> r;
1617 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1619 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1620 return boost::static_pointer_cast<Region> (r);
1624 return boost::shared_ptr<Region>();
1628 Region::apply (Filter& filter)
1630 return filter.run (shared_from_this());
1635 Region::invalidate_transients ()
1637 _valid_transients = false;
1638 _transients.clear ();