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)
64 , _flags(Flag (flags|DoNotSendPropertyChanges))
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)
89 , _flags(Flag (flags|DoNotSendPropertyChanges))
94 , _positional_lock_style(AudioTime)
95 , _sync_position(_start)
97 , _first_edit(EditChangesNothing)
99 , _ancestral_start (0)
100 , _ancestral_length (0)
103 , _valid_transients(false)
104 , _read_data_count(0)
105 , _pending_changed(Change (0))
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)
122 , _flags(Flag (flags|DoNotSendPropertyChanges))
127 , _positional_lock_style(AudioTime)
128 , _sync_position(_start)
130 , _first_edit(EditChangesNothing)
132 , _ancestral_start (0)
133 , _ancestral_length (0)
136 , _read_data_count(0)
137 , _pending_changed(Change (0))
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 _flags = Flag (_flags | DoNotSendPropertyChanges);
155 /* if the other region had a distinct sync point
156 set, then continue to use it as best we can.
157 otherwise, reset sync point back to start.
160 if (other->flags() & SyncMarked) {
161 if (other->_sync_position < _start) {
162 _flags = Flag (_flags & ~SyncMarked);
163 _sync_position = _start;
165 _sync_position = other->_sync_position;
168 _flags = Flag (_flags & ~SyncMarked);
169 _sync_position = _start;
172 if (Profile->get_sae()) {
173 /* reset sync point to start if its ended up
174 outside region bounds.
177 if (_sync_position < _start || _sync_position >= _start + _length) {
178 _flags = Flag (_flags & ~SyncMarked);
179 _sync_position = _start;
184 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
185 : SessionObject(other->session(), name)
186 , _type (other->data_type())
188 /* create a new Region exactly like another but starting at 0 in its sources */
191 copy_stuff (other, 0, length, name, layer, flags);
193 _flags = Flag (_flags | DoNotSendPropertyChanges);
195 /* sync pos is relative to start of file. our start-in-file is now zero,
196 so set our sync position to whatever the the difference between
197 _start and _sync_pos was in the other region.
199 result is that our new sync pos points to the same point in our source(s)
200 as the sync in the other region did in its source(s).
202 since we start at zero in our source(s), it is not possible to use a sync point that
203 is before the start. reset it to _start if that was true in the other region.
206 if (other->flags() & SyncMarked) {
207 if (other->_start < other->_sync_position) {
208 /* sync pos was after the start point of the other region */
209 _sync_position = other->_sync_position - other->_start;
211 /* sync pos was before the start point of the other region. not possible here. */
212 _flags = Flag (_flags & ~SyncMarked);
213 _sync_position = _start;
216 _flags = Flag (_flags & ~SyncMarked);
217 _sync_position = _start;
220 if (Profile->get_sae()) {
221 /* reset sync point to start if its ended up
222 outside region bounds.
225 if (_sync_position < _start || _sync_position >= _start + _length) {
226 _flags = Flag (_flags & ~SyncMarked);
227 _sync_position = _start;
231 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
233 _positional_lock_style = other->_positional_lock_style;
234 _first_edit = other->_first_edit;
237 /** Pure copy constructor */
238 Region::Region (boost::shared_ptr<const Region> other)
239 : SessionObject(other->session(), other->name())
240 , _type(other->data_type())
241 , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
242 , _start(other->_start)
243 , _length(other->_length)
244 , _position(other->_position)
245 , _last_position(other->_last_position)
246 , _positional_lock_style(other->_positional_lock_style)
247 , _sync_position(other->_sync_position)
248 , _layer(other->_layer)
249 , _first_edit(EditChangesID)
251 , _ancestral_start (other->_ancestral_start)
252 , _ancestral_length (other->_ancestral_length)
253 , _stretch (other->_stretch)
254 , _shift (other->_shift)
255 , _valid_transients(false)
256 , _read_data_count(0)
257 , _pending_changed(Change(0))
258 , _last_layer_op(other->_last_layer_op)
260 _flags = Flag (_flags | DoNotSendPropertyChanges);
262 other->_first_edit = EditChangesName;
264 if (other->_extra_xml) {
265 _extra_xml = new XMLNode (*other->_extra_xml);
270 use_sources (other->_sources);
271 assert(_sources.size() > 0);
274 Region::Region (const SourceList& srcs, const XMLNode& node)
275 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
276 , _type(DataType::NIL) // to be loaded from XML
277 , _flags(DoNotSendPropertyChanges)
282 , _positional_lock_style(AudioTime)
283 , _sync_position(_start)
285 , _first_edit(EditChangesNothing)
289 , _read_data_count(0)
290 , _pending_changed(Change(0))
295 if (set_state (node)) {
296 throw failed_constructor();
299 assert(_type != DataType::NIL);
300 assert(_sources.size() > 0);
303 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
304 : SessionObject(src->session(), X_("error: XML did not reset this"))
305 , _type(DataType::NIL)
306 , _flags(DoNotSendPropertyChanges)
311 , _positional_lock_style(AudioTime)
312 , _sync_position(_start)
314 , _first_edit(EditChangesNothing)
318 , _read_data_count(0)
319 , _pending_changed(Change(0))
322 _sources.push_back (src);
324 if (set_state (node)) {
325 throw failed_constructor();
328 assert(_type != DataType::NIL);
329 assert(_sources.size() > 0);
334 boost::shared_ptr<Playlist> pl (playlist());
337 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
338 (*i)->remove_playlist (pl);
340 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
341 (*i)->remove_playlist (pl);
346 GoingAway (); /* EMIT SIGNAL */
350 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
353 _pending_changed = Change (0);
354 _read_data_count = 0;
355 _valid_transients = false;
358 _last_length = length;
359 _sync_position = other->_sync_position;
360 _ancestral_start = other->_ancestral_start;
361 _ancestral_length = other->_ancestral_length;
362 _stretch = other->_stretch;
363 _shift = other->_shift;
368 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
369 _first_edit = EditChangesNothing;
371 _positional_lock_style = AudioTime;
373 use_sources (other->_sources);
377 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
379 boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
381 boost::shared_ptr<Playlist> pl (wpl.lock());
383 if (old_playlist == pl) {
391 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
392 (*i)->remove_playlist (_playlist);
393 (*i)->add_playlist (pl);
395 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
396 (*i)->remove_playlist (_playlist);
397 (*i)->add_playlist (pl);
400 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
401 (*i)->add_playlist (pl);
403 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
404 (*i)->add_playlist (pl);
409 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
410 (*i)->remove_playlist (old_playlist);
412 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
413 (*i)->remove_playlist (old_playlist);
420 Region::set_name (const std::string& str)
423 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
424 assert(_name == str);
425 send_change (ARDOUR::NameChanged);
432 Region::set_length (nframes_t len, void *src)
434 //cerr << "Region::set_length() len = " << len << endl;
435 if (_flags & Locked) {
439 if (_length != len && len != 0) {
441 /* check that the current _position wouldn't make the new
445 if (max_frames - len < _position) {
449 if (!verify_length (len)) {
454 _last_length = _length;
457 _flags = Region::Flag (_flags & ~WholeFile);
461 invalidate_transients ();
467 send_change (LengthChanged);
472 Region::maybe_uncopy ()
477 Region::first_edit ()
479 boost::shared_ptr<Playlist> pl (playlist());
481 if (_first_edit != EditChangesNothing && pl) {
483 _name = pl->session().new_region_name (_name);
484 _first_edit = EditChangesNothing;
486 send_change (ARDOUR::NameChanged);
487 RegionFactory::CheckNewRegion (shared_from_this());
492 Region::at_natural_position () const
494 boost::shared_ptr<Playlist> pl (playlist());
500 boost::shared_ptr<Region> whole_file_region = get_parent();
502 if (whole_file_region) {
503 if (_position == whole_file_region->position() + _start) {
512 Region::move_to_natural_position (void *src)
514 boost::shared_ptr<Playlist> pl (playlist());
520 boost::shared_ptr<Region> whole_file_region = get_parent();
522 if (whole_file_region) {
523 set_position (whole_file_region->position() + _start, src);
528 Region::special_set_position (nframes_t pos)
530 /* this is used when creating a whole file region as
531 a way to store its "natural" or "captured" position.
534 _position = _position;
539 Region::set_position_lock_style (PositionLockStyle ps)
541 boost::shared_ptr<Playlist> pl (playlist());
547 _positional_lock_style = ps;
549 if (_positional_lock_style == MusicTime) {
550 pl->session().tempo_map().bbt_time (_position, _bbt_time);
556 Region::update_position_after_tempo_map_change ()
558 boost::shared_ptr<Playlist> pl (playlist());
560 if (!pl || _positional_lock_style != MusicTime) {
564 TempoMap& map (pl->session().tempo_map());
565 nframes_t pos = map.frame_time (_bbt_time);
566 set_position_internal (pos, false);
570 Region::set_position (nframes_t pos, void *src)
576 set_position_internal (pos, true);
580 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
582 if (_position != pos) {
583 _last_position = _position;
586 /* check that the new _position wouldn't make the current
587 length impossible - if so, change the length.
589 XXX is this the right thing to do?
592 if (max_frames - _length < _position) {
593 _last_length = _length;
594 _length = max_frames - _position;
597 if (allow_bbt_recompute) {
598 recompute_position_from_lock_style ();
601 invalidate_transients ();
604 /* do this even if the position is the same. this helps out
605 a GUI that has moved its representation already.
608 send_change (PositionChanged);
612 Region::set_position_on_top (nframes_t pos, void *src)
614 if (_flags & Locked) {
618 if (_position != pos) {
619 _last_position = _position;
623 boost::shared_ptr<Playlist> pl (playlist());
626 pl->raise_region_to_top (shared_from_this ());
629 /* do this even if the position is the same. this helps out
630 a GUI that has moved its representation already.
633 send_change (PositionChanged);
637 Region::recompute_position_from_lock_style ()
639 if (_positional_lock_style == MusicTime) {
640 boost::shared_ptr<Playlist> pl (playlist());
642 pl->session().tempo_map().bbt_time (_position, _bbt_time);
648 Region::nudge_position (nframes64_t n, void *src)
650 if (_flags & Locked) {
658 _last_position = _position;
661 if (_position > max_frames - n) {
662 _position = max_frames;
667 if (_position < (nframes_t) -n) {
674 send_change (PositionChanged);
678 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
680 _ancestral_length = l;
681 _ancestral_start = s;
687 Region::set_start (nframes_t pos, void *src)
689 if (_flags & (Locked|PositionLocked)) {
692 /* This just sets the start, nothing else. It effectively shifts
693 the contents of the Region within the overall extent of the Source,
694 without changing the Region's position or length
699 if (!verify_start (pos)) {
704 _flags = Region::Flag (_flags & ~WholeFile);
706 invalidate_transients ();
708 send_change (StartChanged);
713 Region::trim_start (nframes_t new_position, void *src)
715 if (_flags & (Locked|PositionLocked)) {
721 if (new_position > _position) {
722 start_shift = new_position - _position;
724 start_shift = -(_position - new_position);
727 if (start_shift > 0) {
729 if (_start > max_frames - start_shift) {
730 new_start = max_frames;
732 new_start = _start + start_shift;
735 if (!verify_start (new_start)) {
739 } else if (start_shift < 0) {
741 if (_start < (nframes_t) -start_shift) {
744 new_start = _start + start_shift;
750 if (new_start == _start) {
755 _flags = Region::Flag (_flags & ~WholeFile);
758 send_change (StartChanged);
762 Region::trim_front (nframes_t new_position, void *src)
764 if (_flags & Locked) {
768 nframes_t end = last_frame();
769 nframes_t source_zero;
771 if (_position > _start) {
772 source_zero = _position - _start;
774 source_zero = 0; // its actually negative, but this will work for us
777 if (new_position < end) { /* can't trim it zero or negative length */
781 /* can't trim it back passed where source position zero is located */
783 new_position = max (new_position, source_zero);
786 if (new_position > _position) {
787 newlen = _length - (new_position - _position);
789 newlen = _length + (_position - new_position);
792 trim_to_internal (new_position, newlen, src);
794 recompute_at_start ();
800 Region::trim_end (nframes_t new_endpoint, void *src)
802 if (_flags & Locked) {
806 if (new_endpoint > _position) {
807 trim_to_internal (_position, new_endpoint - _position, this);
815 Region::trim_to (nframes_t position, nframes_t length, void *src)
817 if (_flags & Locked) {
821 trim_to_internal (position, length, src);
824 recompute_at_start ();
830 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
835 if (_flags & Locked) {
839 if (position > _position) {
840 start_shift = position - _position;
842 start_shift = -(_position - position);
845 if (start_shift > 0) {
847 if (_start > max_frames - start_shift) {
848 new_start = max_frames;
850 new_start = _start + start_shift;
854 } else if (start_shift < 0) {
856 if (_start < (nframes_t) -start_shift) {
859 new_start = _start + start_shift;
865 if (!verify_start_and_length (new_start, length)) {
869 Change what_changed = Change (0);
871 if (_start != new_start) {
873 what_changed = Change (what_changed|StartChanged);
875 if (_length != length) {
877 _last_length = _length;
880 what_changed = Change (what_changed|LengthChanged);
882 if (_position != position) {
884 _last_position = _position;
886 _position = position;
887 what_changed = Change (what_changed|PositionChanged);
890 _flags = Region::Flag (_flags & ~WholeFile);
892 if (what_changed & (StartChanged|LengthChanged)) {
897 send_change (what_changed);
902 Region::set_hidden (bool yn)
904 if (hidden() != yn) {
907 _flags = Flag (_flags|Hidden);
909 _flags = Flag (_flags & ~Hidden);
912 send_change (HiddenChanged);
917 Region::set_muted (bool yn)
922 _flags = Flag (_flags|Muted);
924 _flags = Flag (_flags & ~Muted);
927 send_change (MuteChanged);
932 Region::set_opaque (bool yn)
934 if (opaque() != yn) {
936 _flags = Flag (_flags|Opaque);
938 _flags = Flag (_flags & ~Opaque);
940 send_change (OpacityChanged);
945 Region::set_locked (bool yn)
947 if (locked() != yn) {
949 _flags = Flag (_flags|Locked);
951 _flags = Flag (_flags & ~Locked);
953 send_change (LockChanged);
958 Region::set_position_locked (bool yn)
960 if (position_locked() != yn) {
962 _flags = Flag (_flags|PositionLocked);
964 _flags = Flag (_flags & ~PositionLocked);
966 send_change (LockChanged);
971 Region::set_sync_position (nframes_t absolute_pos)
975 file_pos = _start + (absolute_pos - _position);
977 if (file_pos != _sync_position) {
979 _sync_position = file_pos;
980 _flags = Flag (_flags|SyncMarked);
985 send_change (SyncOffsetChanged);
990 Region::clear_sync_position ()
992 if (_flags & SyncMarked) {
993 _flags = Flag (_flags & ~SyncMarked);
998 send_change (SyncOffsetChanged);
1003 Region::sync_offset (int& dir) const
1005 /* returns the sync point relative the first frame of the region */
1007 if (_flags & SyncMarked) {
1008 if (_sync_position > _start) {
1010 return _sync_position - _start;
1013 return _start - _sync_position;
1022 Region::adjust_to_sync (nframes_t pos) const
1025 nframes_t offset = sync_offset (sync_dir);
1027 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1036 if (max_frames - pos > offset) {
1045 Region::sync_position() const
1047 if (_flags & SyncMarked) {
1048 return _sync_position;
1057 boost::shared_ptr<Playlist> pl (playlist());
1059 pl->raise_region (shared_from_this ());
1066 boost::shared_ptr<Playlist> pl (playlist());
1068 pl->lower_region (shared_from_this ());
1074 Region::raise_to_top ()
1076 boost::shared_ptr<Playlist> pl (playlist());
1078 pl->raise_region_to_top (shared_from_this());
1083 Region::lower_to_bottom ()
1085 boost::shared_ptr<Playlist> pl (playlist());
1087 pl->lower_region_to_bottom (shared_from_this());
1092 Region::set_layer (layer_t l)
1097 send_change (LayerChanged);
1102 Region::state (bool full_state)
1104 XMLNode *node = new XMLNode ("Region");
1106 const char* fe = NULL;
1108 _id.print (buf, sizeof (buf));
1109 node->add_property ("id", buf);
1110 node->add_property ("name", _name);
1111 node->add_property ("type", _type.to_string());
1112 snprintf (buf, sizeof (buf), "%u", _start);
1113 node->add_property ("start", buf);
1114 snprintf (buf, sizeof (buf), "%u", _length);
1115 node->add_property ("length", buf);
1116 snprintf (buf, sizeof (buf), "%u", _position);
1117 node->add_property ("position", buf);
1118 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1119 node->add_property ("ancestral-start", buf);
1120 snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1121 node->add_property ("ancestral-length", buf);
1122 snprintf (buf, sizeof (buf), "%.12g", _stretch);
1123 node->add_property ("stretch", buf);
1124 snprintf (buf, sizeof (buf), "%.12g", _shift);
1125 node->add_property ("shift", buf);
1127 switch (_first_edit) {
1128 case EditChangesNothing:
1131 case EditChangesName:
1137 default: /* should be unreachable but makes g++ happy */
1142 node->add_property ("first-edit", fe);
1144 /* note: flags are stored by derived classes */
1146 snprintf (buf, sizeof (buf), "%d", (int) _layer);
1147 node->add_property ("layer", buf);
1148 snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1149 node->add_property ("sync-position", buf);
1151 if (_positional_lock_style != AudioTime) {
1152 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1155 node->add_property ("bbt-position", str.str());
1162 Region::get_state ()
1164 return state (true);
1168 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
1170 const XMLNodeList& nlist = node.children();
1171 const XMLProperty *prop;
1174 /* this is responsible for setting those aspects of Region state
1175 that are mutable after construction.
1178 if ((prop = node.property ("name")) == 0) {
1179 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
1183 _name = prop->value();
1185 if ((prop = node.property ("type")) == 0) {
1186 _type = DataType::AUDIO;
1188 _type = DataType(prop->value());
1191 if ((prop = node.property ("start")) != 0) {
1192 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1193 if (val != _start) {
1194 what_changed = Change (what_changed|StartChanged);
1201 if ((prop = node.property ("length")) != 0) {
1202 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1203 if (val != _length) {
1204 what_changed = Change (what_changed|LengthChanged);
1205 _last_length = _length;
1209 _last_length = _length;
1213 if ((prop = node.property ("position")) != 0) {
1214 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1215 if (val != _position) {
1216 what_changed = Change (what_changed|PositionChanged);
1217 _last_position = _position;
1221 _last_position = _position;
1225 if ((prop = node.property ("layer")) != 0) {
1227 x = (layer_t) atoi (prop->value().c_str());
1229 what_changed = Change (what_changed|LayerChanged);
1236 if ((prop = node.property ("sync-position")) != 0) {
1237 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1238 if (val != _sync_position) {
1239 what_changed = Change (what_changed|SyncOffsetChanged);
1240 _sync_position = val;
1243 _sync_position = _start;
1246 if ((prop = node.property ("positional-lock-style")) != 0) {
1247 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1249 if (_positional_lock_style == MusicTime) {
1250 if ((prop = node.property ("bbt-position")) == 0) {
1251 /* missing BBT info, revert to audio time locking */
1252 _positional_lock_style = AudioTime;
1254 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1257 &_bbt_time.ticks) != 3) {
1258 _positional_lock_style = AudioTime;
1264 _positional_lock_style = AudioTime;
1267 /* XXX FIRST EDIT !!! */
1269 /* these 3 properties never change as a result of any editing */
1271 if ((prop = node.property ("ancestral-start")) != 0) {
1272 _ancestral_start = strtoll (prop->value().c_str(), 0, 10);
1274 _ancestral_start = _start;
1277 if ((prop = node.property ("ancestral-length")) != 0) {
1278 _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
1280 _ancestral_length = _length;
1283 if ((prop = node.property ("stretch")) != 0) {
1284 _stretch = atof (prop->value());
1286 /* fix problem with old sessions corrupted by an impossible
1289 if (_stretch == 0.0) {
1296 if ((prop = node.property ("shift")) != 0) {
1297 _shift = atof (prop->value());
1299 /* fix problem with old sessions corrupted by an impossible
1302 if (_shift == 0.0) {
1310 /* note: derived classes set flags */
1315 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1321 if (child->name () == "Extra") {
1322 _extra_xml = new XMLNode (*child);
1328 send_change (what_changed);
1335 Region::set_state (const XMLNode& node)
1337 const XMLProperty *prop;
1338 Change what_changed = Change (0);
1340 /* ID is not allowed to change, ever */
1342 if ((prop = node.property ("id")) == 0) {
1343 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
1347 _id = prop->value();
1349 _first_edit = EditChangesNothing;
1351 set_live_state (node, what_changed, true);
1360 _last_length = _length;
1361 _last_position = _position;
1365 Region::thaw (const string& why)
1367 Change what_changed = Change (0);
1370 Glib::Mutex::Lock lm (_lock);
1372 if (_frozen && --_frozen > 0) {
1376 if (_pending_changed) {
1377 what_changed = _pending_changed;
1378 _pending_changed = Change (0);
1382 if (what_changed == Change (0)) {
1386 if (what_changed & LengthChanged) {
1387 if (what_changed & PositionChanged) {
1388 recompute_at_start ();
1390 recompute_at_end ();
1393 StateChanged (what_changed);
1397 Region::send_change (Change what_changed)
1400 Glib::Mutex::Lock lm (_lock);
1402 _pending_changed = Change (_pending_changed|what_changed);
1407 StateChanged (what_changed);
1409 if (!(_flags & DoNotSendPropertyChanges)) {
1411 /* Try and send a shared_pointer unless this is part of the constructor.
1416 boost::shared_ptr<Region> rptr = shared_from_this();
1417 RegionPropertyChanged (rptr);
1419 /* no shared_ptr available, relax; */
1426 Region::set_last_layer_op (uint64_t when)
1428 _last_layer_op = when;
1432 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1434 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1438 Region::equivalent (boost::shared_ptr<const Region> other) const
1440 return _start == other->_start &&
1441 _position == other->_position &&
1442 _length == other->_length;
1446 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1448 return _start == other->_start &&
1449 _length == other->_length;
1453 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1455 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1459 Region::source_deleted (boost::shared_ptr<Source>)
1466 Region::master_source_names ()
1468 SourceList::iterator i;
1470 vector<string> names;
1471 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1472 names.push_back((*i)->name());
1479 Region::set_master_sources (const SourceList& srcs)
1481 _master_sources = srcs;
1482 assert (_sources.size() == _master_sources.size());
1486 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1491 SourceList::const_iterator i;
1492 SourceList::const_iterator io;
1494 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1495 if ((*i)->id() != (*io)->id()) {
1500 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1501 if ((*i)->id() != (*io)->id()) {
1510 Region::source_length(uint32_t n) const
1512 return _sources[n]->length(_position - _start);
1516 Region::verify_length (nframes_t len)
1518 if (source() && (source()->destructive() || source()->length_mutable())) {
1522 nframes_t maxlen = 0;
1524 for (uint32_t n=0; n < _sources.size(); ++n) {
1525 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1528 len = min (len, maxlen);
1534 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1536 if (source() && (source()->destructive() || source()->length_mutable())) {
1540 nframes_t maxlen = 0;
1542 for (uint32_t n=0; n < _sources.size(); ++n) {
1543 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1546 new_length = min (new_length, maxlen);
1552 Region::verify_start (nframes_t pos)
1554 if (source() && (source()->destructive() || source()->length_mutable())) {
1558 for (uint32_t n=0; n < _sources.size(); ++n) {
1559 if (pos > source_length(n) - _length) {
1567 Region::verify_start_mutable (nframes_t& new_start)
1569 if (source() && (source()->destructive() || source()->length_mutable())) {
1573 for (uint32_t n=0; n < _sources.size(); ++n) {
1574 if (new_start > source_length(n) - _length) {
1575 new_start = source_length(n) - _length;
1581 boost::shared_ptr<Region>
1582 Region::get_parent() const
1584 boost::shared_ptr<Playlist> pl (playlist());
1587 boost::shared_ptr<Region> r;
1588 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1590 if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
1591 return boost::static_pointer_cast<Region> (r);
1595 return boost::shared_ptr<Region>();
1599 Region::apply (Filter& filter)
1601 return filter.run (shared_from_this());
1606 Region::invalidate_transients ()
1608 _valid_transients = false;
1609 _transients.clear ();
1614 Region::use_sources (SourceList const & s)
1616 set<boost::shared_ptr<Source> > unique_srcs;
1618 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1619 _sources.push_back (*i);
1620 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));
1621 unique_srcs.insert (*i);
1624 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1625 _master_sources.push_back (*i);
1626 if (unique_srcs.find (*i) == unique_srcs.end()) {
1627 (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));