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>
45 using namespace ARDOUR;
48 Change Region::FadeChanged = ARDOUR::new_change ();
49 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
50 Change Region::MuteChanged = ARDOUR::new_change ();
51 Change Region::OpacityChanged = ARDOUR::new_change ();
52 Change Region::LockChanged = ARDOUR::new_change ();
53 Change Region::LayerChanged = ARDOUR::new_change ();
54 Change Region::HiddenChanged = ARDOUR::new_change ();
56 sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
58 /* derived-from-derived constructor (no sources in constructor) */
59 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
60 : SessionObject(s, name)
67 , _positional_lock_style(AudioTime)
68 , _sync_position(_start)
70 , _first_edit(EditChangesNothing)
75 , _pending_changed(Change (0))
78 /* no sources at this point */
81 /** Basic Region constructor (single source) */
82 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
83 : SessionObject(src->session(), name)
90 , _positional_lock_style(AudioTime)
91 , _sync_position(_start)
93 , _first_edit(EditChangesNothing)
95 , _ancestral_start (start)
96 , _ancestral_length (length)
99 , _valid_transients(false)
100 , _read_data_count(0)
101 , _pending_changed(Change (0))
105 _sources.push_back (src);
106 _master_sources.push_back (src);
108 src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
110 assert(_sources.size() > 0);
111 _positional_lock_style = AudioTime;
114 /** Basic Region constructor (many sources) */
115 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
116 : SessionObject(srcs.front()->session(), name)
123 , _positional_lock_style(AudioTime)
124 , _sync_position(_start)
126 , _first_edit(EditChangesNothing)
130 , _read_data_count(0)
131 , _pending_changed(Change (0))
135 set<boost::shared_ptr<Source> > unique_srcs;
137 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
138 _sources.push_back (*i);
139 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
140 unique_srcs.insert (*i);
143 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
144 _master_sources.push_back (*i);
145 if (unique_srcs.find (*i) == unique_srcs.end()) {
146 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
150 assert(_sources.size() > 0);
153 /** Create a new Region from part of an existing one */
154 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
155 : SessionObject(other->session(), name)
156 , _type(other->data_type())
157 , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
158 , _start(other->_start + offset)
162 , _positional_lock_style(other->_positional_lock_style)
163 , _sync_position(_start)
165 , _first_edit(EditChangesNothing)
167 , _ancestral_start (other->_ancestral_start + offset)
168 , _ancestral_length (length)
169 , _stretch (other->_stretch)
170 , _shift (other->_shift)
171 , _valid_transients(false)
172 , _read_data_count(0)
173 , _pending_changed(Change (0))
176 if (other->_sync_position < offset)
177 _sync_position = other->_sync_position;
179 set<boost::shared_ptr<Source> > unique_srcs;
181 for (SourceList::const_iterator i= other->_sources.begin(); i != other->_sources.end(); ++i) {
182 _sources.push_back (*i);
183 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
184 unique_srcs.insert (*i);
187 if (other->_sync_position < offset) {
188 _sync_position = other->_sync_position;
192 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
193 if (unique_srcs.find (*i) == unique_srcs.end()) {
194 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
196 _master_sources.push_back (*i);
199 assert(_sources.size() > 0);
202 /** Pure copy constructor */
203 Region::Region (boost::shared_ptr<const Region> other)
204 : SessionObject(other->session(), other->name())
205 , _type(other->data_type())
206 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
207 , _start(other->_start)
208 , _length(other->_length)
209 , _position(other->_position)
210 , _last_position(other->_last_position)
211 , _positional_lock_style(other->_positional_lock_style)
212 , _sync_position(other->_sync_position)
213 , _layer(other->_layer)
214 , _first_edit(EditChangesID)
216 , _ancestral_start (other->_ancestral_start)
217 , _ancestral_length (other->_ancestral_length)
218 , _stretch (other->_stretch)
219 , _shift (other->_shift)
220 , _valid_transients(false)
221 , _read_data_count(0)
222 , _pending_changed(Change(0))
223 , _last_layer_op(other->_last_layer_op)
225 other->_first_edit = EditChangesName;
227 if (other->_extra_xml) {
228 _extra_xml = new XMLNode (*other->_extra_xml);
233 set<boost::shared_ptr<Source> > unique_srcs;
235 for (SourceList::const_iterator i = other->_sources.begin(); i != other->_sources.end(); ++i) {
236 _sources.push_back (*i);
237 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
238 unique_srcs.insert (*i);
241 for (SourceList::const_iterator i = other->_master_sources.begin(); i != other->_master_sources.end(); ++i) {
242 _master_sources.push_back (*i);
243 if (unique_srcs.find (*i) == unique_srcs.end()) {
244 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
248 assert(_sources.size() > 0);
251 Region::Region (const SourceList& srcs, const XMLNode& node)
252 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
253 , _type(DataType::NIL) // to be loaded from XML
259 , _positional_lock_style(AudioTime)
260 , _sync_position(_start)
262 , _first_edit(EditChangesNothing)
266 , _read_data_count(0)
267 , _pending_changed(Change(0))
270 set<boost::shared_ptr<Source> > unique_srcs;
272 for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
273 _sources.push_back (*i);
274 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
275 unique_srcs.insert (*i);
278 for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
279 _master_sources.push_back (*i);
280 if (unique_srcs.find (*i) == unique_srcs.end()) {
281 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
285 if (set_state (node)) {
286 throw failed_constructor();
289 assert(_type != DataType::NIL);
290 assert(_sources.size() > 0);
293 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
294 : SessionObject(src->session(), X_("error: XML did not reset this"))
295 , _type(DataType::NIL)
301 , _positional_lock_style(AudioTime)
302 , _sync_position(_start)
304 , _first_edit(EditChangesNothing)
308 , _read_data_count(0)
309 , _pending_changed(Change(0))
312 _sources.push_back (src);
314 if (set_state (node)) {
315 throw failed_constructor();
318 assert(_type != DataType::NIL);
319 assert(_sources.size() > 0);
324 boost::shared_ptr<Playlist> pl (playlist());
327 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
328 (*i)->remove_playlist (pl);
330 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
331 (*i)->remove_playlist (pl);
336 GoingAway (); /* EMIT SIGNAL */
340 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
342 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
344 boost::shared_ptr<Playlist> pl (wpl.lock());
346 if (old_playlist == pl) {
354 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
355 (*i)->remove_playlist (_playlist);
356 (*i)->add_playlist (pl);
358 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
359 (*i)->remove_playlist (_playlist);
360 (*i)->add_playlist (pl);
363 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
364 (*i)->add_playlist (pl);
366 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
367 (*i)->add_playlist (pl);
372 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
373 (*i)->remove_playlist (old_playlist);
375 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
376 (*i)->remove_playlist (old_playlist);
383 Region::set_name (const std::string& str)
386 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
387 assert(_name == str);
388 send_change (ARDOUR::NameChanged);
395 Region::set_length (nframes_t len, void *src)
397 //cerr << "Region::set_length() len = " << len << endl;
398 if (_flags & Locked) {
402 if (_length != len && len != 0) {
404 /* check that the current _position wouldn't make the new
408 if (max_frames - len < _position) {
412 if (!verify_length (len)) {
417 _last_length = _length;
420 _flags = Region::Flag (_flags & ~WholeFile);
424 invalidate_transients ();
430 send_change (LengthChanged);
435 Region::maybe_uncopy ()
440 Region::first_edit ()
442 boost::shared_ptr<Playlist> pl (playlist());
444 if (_first_edit != EditChangesNothing && pl) {
446 _name = pl->session().new_region_name (_name);
447 _first_edit = EditChangesNothing;
449 send_change (ARDOUR::NameChanged);
450 RegionFactory::CheckNewRegion (shared_from_this());
455 Region::at_natural_position () const
457 boost::shared_ptr<Playlist> pl (playlist());
463 boost::shared_ptr<Region> whole_file_region = get_parent();
465 if (whole_file_region) {
466 if (_position == whole_file_region->position() + _start) {
475 Region::move_to_natural_position (void *src)
477 boost::shared_ptr<Playlist> pl (playlist());
483 boost::shared_ptr<Region> whole_file_region = get_parent();
485 if (whole_file_region) {
486 set_position (whole_file_region->position() + _start, src);
491 Region::special_set_position (nframes_t pos)
493 /* this is used when creating a whole file region as
494 a way to store its "natural" or "captured" position.
497 _position = _position;
502 Region::set_position_lock_style (PositionLockStyle ps)
504 boost::shared_ptr<Playlist> pl (playlist());
510 _positional_lock_style = ps;
512 if (_positional_lock_style == MusicTime) {
513 pl->session().tempo_map().bbt_time (_position, _bbt_time);
519 Region::update_position_after_tempo_map_change ()
521 boost::shared_ptr<Playlist> pl (playlist());
523 if (!pl || _positional_lock_style != MusicTime) {
527 TempoMap& map (pl->session().tempo_map());
528 nframes_t pos = map.frame_time (_bbt_time);
529 set_position_internal (pos, false);
533 Region::set_position (nframes_t pos, void *src)
539 set_position_internal (pos, true);
543 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
545 if (_position != pos) {
546 _last_position = _position;
549 /* check that the new _position wouldn't make the current
550 length impossible - if so, change the length.
552 XXX is this the right thing to do?
555 if (max_frames - _length < _position) {
556 _last_length = _length;
557 _length = max_frames - _position;
560 if (allow_bbt_recompute) {
561 recompute_position_from_lock_style ();
564 invalidate_transients ();
567 /* do this even if the position is the same. this helps out
568 a GUI that has moved its representation already.
571 send_change (PositionChanged);
575 Region::set_position_on_top (nframes_t pos, void *src)
577 if (_flags & Locked) {
581 if (_position != pos) {
582 _last_position = _position;
586 boost::shared_ptr<Playlist> pl (playlist());
589 pl->raise_region_to_top (shared_from_this ());
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::recompute_position_from_lock_style ()
602 if (_positional_lock_style == MusicTime) {
603 boost::shared_ptr<Playlist> pl (playlist());
605 pl->session().tempo_map().bbt_time (_position, _bbt_time);
611 Region::nudge_position (nframes64_t n, void *src)
613 if (_flags & Locked) {
621 _last_position = _position;
624 if (_position > max_frames - n) {
625 _position = max_frames;
630 if (_position < (nframes_t) -n) {
637 send_change (PositionChanged);
641 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
643 _ancestral_length = l;
644 _ancestral_start = s;
650 Region::set_start (nframes_t pos, void *src)
652 if (_flags & (Locked|PositionLocked)) {
655 /* This just sets the start, nothing else. It effectively shifts
656 the contents of the Region within the overall extent of the Source,
657 without changing the Region's position or length
662 if (!verify_start (pos)) {
667 _flags = Region::Flag (_flags & ~WholeFile);
669 invalidate_transients ();
671 send_change (StartChanged);
676 Region::trim_start (nframes_t new_position, void *src)
678 if (_flags & (Locked|PositionLocked)) {
684 if (new_position > _position) {
685 start_shift = new_position - _position;
687 start_shift = -(_position - new_position);
690 if (start_shift > 0) {
692 if (_start > max_frames - start_shift) {
693 new_start = max_frames;
695 new_start = _start + start_shift;
698 if (!verify_start (new_start)) {
702 } else if (start_shift < 0) {
704 if (_start < (nframes_t) -start_shift) {
707 new_start = _start + start_shift;
713 if (new_start == _start) {
718 _flags = Region::Flag (_flags & ~WholeFile);
721 send_change (StartChanged);
725 Region::trim_front (nframes_t new_position, void *src)
727 if (_flags & Locked) {
731 nframes_t end = last_frame();
732 nframes_t source_zero;
734 if (_position > _start) {
735 source_zero = _position - _start;
737 source_zero = 0; // its actually negative, but this will work for us
740 if (new_position < end) { /* can't trim it zero or negative length */
744 /* can't trim it back passed where source position zero is located */
746 new_position = max (new_position, source_zero);
749 if (new_position > _position) {
750 newlen = _length - (new_position - _position);
752 newlen = _length + (_position - new_position);
755 trim_to_internal (new_position, newlen, src);
757 recompute_at_start ();
763 Region::trim_end (nframes_t new_endpoint, void *src)
765 if (_flags & Locked) {
769 if (new_endpoint > _position) {
770 trim_to_internal (_position, new_endpoint - _position, this);
778 Region::trim_to (nframes_t position, nframes_t length, void *src)
780 if (_flags & Locked) {
784 trim_to_internal (position, length, src);
787 recompute_at_start ();
793 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
798 if (_flags & Locked) {
802 if (position > _position) {
803 start_shift = position - _position;
805 start_shift = -(_position - position);
808 if (start_shift > 0) {
810 if (_start > max_frames - start_shift) {
811 new_start = max_frames;
813 new_start = _start + start_shift;
817 } else if (start_shift < 0) {
819 if (_start < (nframes_t) -start_shift) {
822 new_start = _start + start_shift;
828 if (!verify_start_and_length (new_start, length)) {
832 Change what_changed = Change (0);
834 if (_start != new_start) {
836 what_changed = Change (what_changed|StartChanged);
838 if (_length != length) {
840 _last_length = _length;
843 what_changed = Change (what_changed|LengthChanged);
845 if (_position != position) {
847 _last_position = _position;
849 _position = position;
850 what_changed = Change (what_changed|PositionChanged);
853 _flags = Region::Flag (_flags & ~WholeFile);
855 if (what_changed & (StartChanged|LengthChanged)) {
860 send_change (what_changed);
865 Region::set_hidden (bool yn)
867 if (hidden() != yn) {
870 _flags = Flag (_flags|Hidden);
872 _flags = Flag (_flags & ~Hidden);
875 send_change (HiddenChanged);
880 Region::set_muted (bool yn)
885 _flags = Flag (_flags|Muted);
887 _flags = Flag (_flags & ~Muted);
890 send_change (MuteChanged);
895 Region::set_opaque (bool yn)
897 if (opaque() != yn) {
899 _flags = Flag (_flags|Opaque);
901 _flags = Flag (_flags & ~Opaque);
903 send_change (OpacityChanged);
908 Region::set_locked (bool yn)
910 if (locked() != yn) {
912 _flags = Flag (_flags|Locked);
914 _flags = Flag (_flags & ~Locked);
916 send_change (LockChanged);
921 Region::set_position_locked (bool yn)
923 if (position_locked() != yn) {
925 _flags = Flag (_flags|PositionLocked);
927 _flags = Flag (_flags & ~PositionLocked);
929 send_change (LockChanged);
934 Region::set_sync_position (nframes_t absolute_pos)
938 file_pos = _start + (absolute_pos - _position);
940 if (file_pos != _sync_position) {
942 _sync_position = file_pos;
943 _flags = Flag (_flags|SyncMarked);
948 send_change (SyncOffsetChanged);
953 Region::clear_sync_position ()
955 if (_flags & SyncMarked) {
956 _flags = Flag (_flags & ~SyncMarked);
961 send_change (SyncOffsetChanged);
966 Region::sync_offset (int& dir) const
968 /* returns the sync point relative the first frame of the region */
970 if (_flags & SyncMarked) {
971 if (_sync_position > _start) {
973 return _sync_position - _start;
976 return _start - _sync_position;
985 Region::adjust_to_sync (nframes_t pos)
988 nframes_t offset = sync_offset (sync_dir);
990 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
999 if (max_frames - pos > offset) {
1008 Region::sync_position() const
1010 if (_flags & SyncMarked) {
1011 return _sync_position;
1020 boost::shared_ptr<Playlist> pl (playlist());
1022 pl->raise_region (shared_from_this ());
1029 boost::shared_ptr<Playlist> pl (playlist());
1031 pl->lower_region (shared_from_this ());
1037 Region::raise_to_top ()
1039 boost::shared_ptr<Playlist> pl (playlist());
1041 pl->raise_region_to_top (shared_from_this());
1046 Region::lower_to_bottom ()
1048 boost::shared_ptr<Playlist> pl (playlist());
1050 pl->lower_region_to_bottom (shared_from_this());
1055 Region::set_layer (layer_t l)
1060 send_change (LayerChanged);
1065 Region::state (bool full_state)
1067 XMLNode *node = new XMLNode ("Region");
1069 const char* fe = NULL;
1071 _id.print (buf, sizeof (buf));
1072 node->add_property ("id", buf);
1073 node->add_property ("name", _name);
1074 node->add_property ("type", _type.to_string());
1075 snprintf (buf, sizeof (buf), "%u", _start);
1076 node->add_property ("start", buf);
1077 snprintf (buf, sizeof (buf), "%u", _length);
1078 node->add_property ("length", buf);
1079 snprintf (buf, sizeof (buf), "%u", _position);
1080 node->add_property ("position", buf);
1081 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1082 node->add_property ("ancestral-start", buf);
1083 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1084 node->add_property ("ancestral-length", buf);
1085 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1086 node->add_property ("stretch", buf);
1087 snprintf (buf, sizeof (buf), "%.12g", _shift);
1088 node->add_property ("shift", buf);
1090 switch (_first_edit) {
1091 case EditChangesNothing:
1094 case EditChangesName:
1100 default: /* should be unreachable but makes g++ happy */
1105 node->add_property ("first-edit", fe);
1107 /* note: flags are stored by derived classes */
1109 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1110 node->add_property ("layer", buf);
1111 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1112 node->add_property ("sync-position", buf);
1114 if (_positional_lock_style != AudioTime) {
1115 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1118 node->add_property ("bbt-position", str.str());
1125 Region::get_state ()
1127 return state (true);
1131 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1133 const XMLNodeList& nlist = node.children();
1134 const XMLProperty *prop;
1137 /* this is responsible for setting those aspects of Region state
1138 that are mutable after construction.
1141 if ((prop = node.property ("name")) == 0) {
1142 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1146 _name = prop->value();
1148 if ((prop = node.property ("type")) == 0) {
1149 _type = DataType::AUDIO;
1151 _type = DataType(prop->value());
1154 if ((prop = node.property ("start")) != 0) {
1155 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1156 if (val != _start) {
1157 what_changed = Change (what_changed|StartChanged);
1164 if ((prop = node.property ("length")) != 0) {
1165 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1166 if (val != _length) {
1167 what_changed = Change (what_changed|LengthChanged);
1168 _last_length = _length;
1172 _last_length = _length;
1176 if ((prop = node.property ("position")) != 0) {
1177 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1178 if (val != _position) {
1179 what_changed = Change (what_changed|PositionChanged);
1180 _last_position = _position;
1184 _last_position = _position;
1188 if ((prop = node.property ("layer")) != 0) {
1190 x = (layer_t) atoi (prop->value().c_str());
1192 what_changed = Change (what_changed|LayerChanged);
1199 if ((prop = node.property ("sync-position")) != 0) {
1200 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1201 if (val != _sync_position) {
1202 what_changed = Change (what_changed|SyncOffsetChanged);
1203 _sync_position = val;
1206 _sync_position = _start;
1209 if ((prop = node.property ("positional-lock-style")) != 0) {
1210 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1212 if (_positional_lock_style == MusicTime) {
1213 if ((prop = node.property ("bbt-position")) == 0) {
1214 /* missing BBT info, revert to audio time locking */
1215 _positional_lock_style = AudioTime;
1217 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1220 &_bbt_time.ticks) != 3) {
1221 _positional_lock_style = AudioTime;
1227 _positional_lock_style = AudioTime;
1230 /* XXX FIRST EDIT !!! */
1232 /* these 3 properties never change as a result of any editing */
1234 if ((prop = node.property ("ancestral-start")) != 0) {
1235 _ancestral_start = atoi (prop->value());
1237 _ancestral_start = _start;
1240 if ((prop = node.property ("ancestral-length")) != 0) {
1241 _ancestral_length = atoi (prop->value());
1243 _ancestral_length = _length;
1246 if ((prop = node.property ("stretch")) != 0) {
1247 _stretch = atof (prop->value());
1248 if( _stretch == 0.0 )
1254 if ((prop = node.property ("shift")) != 0) {
1255 _shift = atof (prop->value());
1263 /* note: derived classes set flags */
1270 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1276 if (child->name () == "extra") {
1277 _extra_xml = new XMLNode (*child);
1283 send_change (what_changed);
1290 Region::set_state (const XMLNode& node)
1292 const XMLProperty *prop;
1293 Change what_changed = Change (0);
1295 /* ID is not allowed to change, ever */
1297 if ((prop = node.property ("id")) == 0) {
1298 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1302 _id = prop->value();
1304 _first_edit = EditChangesNothing;
1306 set_live_state (node, what_changed, true);
1315 _last_length = _length;
1316 _last_position = _position;
1320 Region::thaw (const string& why)
1322 Change what_changed = Change (0);
1325 Glib::Mutex::Lock lm (_lock);
1327 if (_frozen && --_frozen > 0) {
1331 if (_pending_changed) {
1332 what_changed = _pending_changed;
1333 _pending_changed = Change (0);
1337 if (what_changed == Change (0)) {
1341 if (what_changed & LengthChanged) {
1342 if (what_changed & PositionChanged) {
1343 recompute_at_start ();
1345 recompute_at_end ();
1348 StateChanged (what_changed);
1352 Region::send_change (Change what_changed)
1355 Glib::Mutex::Lock lm (_lock);
1357 _pending_changed = Change (_pending_changed|what_changed);
1362 StateChanged (what_changed);
1364 if (!(_flags & DoNotSaveState)) {
1366 /* Try and send a shared_pointer unless this is part of the constructor.
1371 boost::shared_ptr<Region> rptr = shared_from_this();
1372 RegionPropertyChanged (rptr);
1374 /* no shared_ptr available, relax; */
1381 Region::set_last_layer_op (uint64_t when)
1383 _last_layer_op = when;
1387 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1389 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1393 Region::equivalent (boost::shared_ptr<const Region> other) const
1395 return _start == other->_start &&
1396 _position == other->_position &&
1397 _length == other->_length;
1401 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1403 return _start == other->_start &&
1404 _length == other->_length;
1408 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1410 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1414 Region::source_deleted (boost::shared_ptr<Source>)
1421 Region::master_source_names ()
1423 SourceList::iterator i;
1425 vector<string> names;
1426 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1427 names.push_back((*i)->name());
1434 Region::set_master_sources (const SourceList& srcs)
1436 _master_sources = srcs;
1440 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1445 SourceList::const_iterator i;
1446 SourceList::const_iterator io;
1448 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1449 if ((*i)->id() != (*io)->id()) {
1454 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1455 if ((*i)->id() != (*io)->id()) {
1464 Region::verify_length (nframes_t len)
1466 if (source() && (source()->destructive() || source()->length_mutable())) {
1470 nframes_t maxlen = 0;
1472 for (uint32_t n=0; n < _sources.size(); ++n) {
1473 maxlen = max (maxlen, _sources[n]->length() - _start);
1476 len = min (len, maxlen);
1482 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1484 if (source() && (source()->destructive() || source()->length_mutable())) {
1488 nframes_t maxlen = 0;
1490 for (uint32_t n=0; n < _sources.size(); ++n) {
1491 maxlen = max (maxlen, _sources[n]->length() - new_start);
1494 new_length = min (new_length, maxlen);
1500 Region::verify_start (nframes_t pos)
1502 if (source() && (source()->destructive() || source()->length_mutable())) {
1506 for (uint32_t n=0; n < _sources.size(); ++n) {
1507 if (pos > _sources[n]->length() - _length) {
1515 Region::verify_start_mutable (nframes_t& new_start)
1517 if (source() && (source()->destructive() || source()->length_mutable())) {
1521 for (uint32_t n=0; n < _sources.size(); ++n) {
1522 if (new_start > _sources[n]->length() - _length) {
1523 new_start = _sources[n]->length() - _length;
1529 boost::shared_ptr<Region>
1530 Region::get_parent() const
1532 boost::shared_ptr<Playlist> pl (playlist());
1535 boost::shared_ptr<Region> r;
1536 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1538 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1539 return boost::static_pointer_cast<Region> (r);
1543 return boost::shared_ptr<Region>();
1547 Region::apply (Filter& filter)
1549 return filter.run (shared_from_this());
1554 Region::invalidate_transients ()
1556 _valid_transients = false;
1557 _transients.clear ();