2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <glibmm/thread.h>
28 #include "pbd/xml++.h"
29 #include "pbd/stacktrace.h"
30 #include "pbd/enumwriter.h"
32 #include "ardour/debug.h"
33 #include "ardour/region.h"
34 #include "ardour/playlist.h"
35 #include "ardour/session.h"
36 #include "ardour/source.h"
37 #include "ardour/tempo.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/filter.h"
40 #include "ardour/profile.h"
41 #include "ardour/utils.h"
46 using namespace ARDOUR;
49 Change Region::FadeChanged = PBD::new_change ();
50 Change Region::SyncOffsetChanged = PBD::new_change ();
51 Change Region::MuteChanged = PBD::new_change ();
52 Change Region::OpacityChanged = PBD::new_change ();
53 Change Region::LockChanged = PBD::new_change ();
54 Change Region::LayerChanged = PBD::new_change ();
55 Change Region::HiddenChanged = PBD::new_change ();
57 PBD::Signal1<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
60 Region::register_states ()
62 _xml_node_name = X_("Region");
66 add_state (_position);
67 add_state (_sync_position);
69 add_state (_ancestral_start);
70 add_state (_ancestral_length);
75 /* derived-from-derived constructor (no sources in constructor) */
76 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
77 : SessionObject(s, name)
79 , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
80 , _start (X_("start"), StartChanged, start)
81 , _length (X_("length"), LengthChanged, length)
82 , _position (X_("position"), PositionChanged, 0)
84 , _positional_lock_style(AudioTime)
85 , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
86 , _layer (X_("layer"), LayerChanged, layer)
87 , _first_edit(EditChangesNothing)
89 , _ancestral_start (X_("ancestral-start"), Change (0), 0)
90 , _ancestral_length (X_("ancestral-length"), Change (0), 0)
91 , _stretch (X_("stretch"), Change (0), 1.0)
92 , _shift (X_("shift"), Change (0), 1.0)
94 , _pending_changed(Change (0))
96 , _pending_explicit_relayer (false)
100 /* no sources at this point */
103 /** Basic Region constructor (single source) */
104 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
105 : SessionObject(src->session(), name)
107 , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
108 , _start (X_("start"), StartChanged, start)
109 , _length (X_("length"), LengthChanged, length)
110 , _position (X_("position"), PositionChanged, 0)
112 , _positional_lock_style(AudioTime)
113 , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
114 , _layer (X_("layer"), LayerChanged, layer)
115 , _first_edit(EditChangesNothing)
117 , _ancestral_start (X_("ancestral-start"), Change (0), 0)
118 , _ancestral_length (X_("ancestral-length"), Change (0), 0)
119 , _stretch (X_("stretch"), Change (0), 1.0)
120 , _shift (X_("shift"), Change (0), 1.0)
121 , _valid_transients(false)
122 , _read_data_count(0)
123 , _pending_changed(Change (0))
125 , _pending_explicit_relayer (false)
129 _sources.push_back (src);
130 _master_sources.push_back (src);
132 src->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
134 assert(_sources.size() > 0);
135 _positional_lock_style = AudioTime;
138 /** Basic Region constructor (many sources) */
139 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
140 : SessionObject(srcs.front()->session(), name)
142 , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
143 , _start (X_("start"), StartChanged, start)
144 , _length (X_("length"), LengthChanged, length)
145 , _position (X_("position"), PositionChanged, 0)
147 , _positional_lock_style(AudioTime)
148 , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
149 , _layer (X_("layer"), LayerChanged, layer)
150 , _first_edit(EditChangesNothing)
152 , _ancestral_start (X_("ancestral-start"), Change (0), 0)
153 , _ancestral_length (X_("ancestral-length"), Change (0), 0)
154 , _stretch (X_("stretch"), Change (0), 1.0)
155 , _shift (X_("shift"), Change (0), 1.0)
156 , _read_data_count(0)
157 , _pending_changed(Change (0))
159 , _pending_explicit_relayer (false)
164 assert(_sources.size() > 0);
167 /** Create a new Region from part of an existing one */
168 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
169 : SessionObject(other->session(), name)
170 , _type (other->data_type())
171 , _flags (X_("flags"), FlagsChanged, Flag (flags | DoNotSendPropertyChanges))
172 , _start (X_("start"), StartChanged, 0)
173 , _length (X_("length"), LengthChanged, 0)
174 , _position (X_("position"), PositionChanged, 0)
175 , _sync_position (X_("sync-position"), SyncOffsetChanged, 0)
176 , _layer (X_("layer"), LayerChanged, 0)
177 , _ancestral_start (X_("ancestral-start"), Change (0), 0)
178 , _ancestral_length (X_("ancestral-length"), Change (0), 0)
179 , _stretch (X_("stretch"), Change (0), 1.0)
180 , _shift (X_("shift"), Change (0), 1.0)
181 , _pending_explicit_relayer (false)
186 _start = other->_start + offset;
187 copy_stuff (other, offset, length, name, layer, flags);
189 /* if the other region had a distinct sync point
190 set, then continue to use it as best we can.
191 otherwise, reset sync point back to start.
194 if (other->flags() & SyncMarked) {
195 if (other->_sync_position < _start) {
196 _flags = Flag (_flags & ~SyncMarked);
197 _sync_position = _start;
199 _sync_position = other->_sync_position;
202 _flags = Flag (_flags & ~SyncMarked);
203 _sync_position = _start;
206 if (Profile->get_sae()) {
207 /* reset sync point to start if its ended up
208 outside region bounds.
211 if (_sync_position < _start || _sync_position >= _start + _length) {
212 _flags = Flag (_flags & ~SyncMarked);
213 _sync_position = _start;
218 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
219 : SessionObject(other->session(), name)
220 , _type (other->data_type())
221 , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
222 , _start (X_("start"), StartChanged, 0)
223 , _length (X_("length"), LengthChanged, 0)
224 , _position (X_("position"), PositionChanged, 0)
225 , _sync_position (X_("sync-position"), SyncOffsetChanged, 0)
226 , _layer (X_("layer"), LayerChanged, 0)
227 , _ancestral_start (X_("ancestral-start"), Change (0), 0)
228 , _ancestral_length (X_("ancestral-length"), Change (0), 0)
229 , _stretch (X_("stretch"), Change (0), 1.0)
230 , _shift (X_("shift"), Change (0), 1.0)
231 , _pending_explicit_relayer (false)
235 /* create a new Region exactly like another but starting at 0 in its sources */
238 copy_stuff (other, 0, length, name, layer, flags);
240 _flags = Flag (_flags | DoNotSendPropertyChanges);
242 /* sync pos is relative to start of file. our start-in-file is now zero,
243 so set our sync position to whatever the the difference between
244 _start and _sync_pos was in the other region.
246 result is that our new sync pos points to the same point in our source(s)
247 as the sync in the other region did in its source(s).
249 since we start at zero in our source(s), it is not possible to use a sync point that
250 is before the start. reset it to _start if that was true in the other region.
253 if (other->flags() & SyncMarked) {
254 if (other->_start < other->_sync_position) {
255 /* sync pos was after the start point of the other region */
256 _sync_position = other->_sync_position - other->_start;
258 /* sync pos was before the start point of the other region. not possible here. */
259 _flags = Flag (_flags & ~SyncMarked);
260 _sync_position = _start;
263 _flags = Flag (_flags & ~SyncMarked);
264 _sync_position = _start;
267 if (Profile->get_sae()) {
268 /* reset sync point to start if its ended up
269 outside region bounds.
272 if (_sync_position < _start || _sync_position >= _start + _length) {
273 _flags = Flag (_flags & ~SyncMarked);
274 _sync_position = _start;
278 /* reset a couple of things that copy_stuff() gets wrong in this particular case */
280 _positional_lock_style = other->_positional_lock_style;
281 _first_edit = other->_first_edit;
284 /** Pure copy constructor */
285 Region::Region (boost::shared_ptr<const Region> other)
286 : SessionObject(other->session(), other->name())
287 , _type(other->data_type())
288 , _flags (other->_flags)
289 , _start(other->_start)
290 , _length(other->_length)
291 , _position(other->_position)
292 , _last_position(other->_last_position)
293 , _positional_lock_style(other->_positional_lock_style)
294 , _sync_position(other->_sync_position)
295 , _layer(other->_layer)
296 , _first_edit(EditChangesID)
298 , _ancestral_start (other->_ancestral_start)
299 , _ancestral_length (other->_ancestral_length)
300 , _stretch (other->_stretch)
301 , _shift (other->_shift)
302 , _valid_transients(false)
303 , _read_data_count(0)
304 , _pending_changed(Change(0))
305 , _last_layer_op(other->_last_layer_op)
306 , _pending_explicit_relayer (false)
310 _flags = Flag (_flags & ~ (Locked | PositionLocked));
311 _flags = Flag (_flags | DoNotSendPropertyChanges);
313 other->_first_edit = EditChangesName;
315 if (other->_extra_xml) {
316 _extra_xml = new XMLNode (*other->_extra_xml);
321 use_sources (other->_sources);
322 assert(_sources.size() > 0);
325 Region::Region (const SourceList& srcs, const XMLNode& node)
326 : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
327 , _type(DataType::NIL) // to be loaded from XML
328 , _flags (X_("flags"), FlagsChanged, Flag (DoNotSendPropertyChanges))
329 , _start (X_("start"), StartChanged, 0)
330 , _length (X_("length"), LengthChanged, 0)
331 , _position (X_("position"), PositionChanged, 0)
333 , _positional_lock_style(AudioTime)
334 , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
335 , _layer (X_("layer"), LayerChanged, 0)
336 , _first_edit(EditChangesNothing)
338 , _ancestral_start (X_("ancestral-start"), Change (0), 0)
339 , _ancestral_length (X_("ancestral-length"), Change (0), 0)
340 , _stretch (X_("stretch"), Change (0), 1.0)
341 , _shift (X_("shift"), Change (0), 1.0)
342 , _read_data_count(0)
343 , _pending_changed(Change(0))
345 , _pending_explicit_relayer (false)
351 if (set_state (node, Stateful::loading_state_version)) {
352 throw failed_constructor();
355 assert(_type != DataType::NIL);
356 assert(_sources.size() > 0);
359 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
360 : SessionObject(src->session(), X_("error: XML did not reset this"))
361 , _type(DataType::NIL)
362 , _flags (X_("flags"), FlagsChanged, Flag (DoNotSendPropertyChanges))
363 , _start (X_("start"), StartChanged, 0)
364 , _length (X_("length"), LengthChanged, 0)
365 , _position (X_("position"), PositionChanged, 0)
367 , _positional_lock_style(AudioTime)
368 , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
369 , _layer (X_("layer"), LayerChanged, 0)
370 , _first_edit(EditChangesNothing)
372 , _ancestral_start (X_("ancestral-start"), Change (0), 0)
373 , _ancestral_length (X_("ancestral-length"), Change (0), 0)
374 , _stretch (X_("stretch"), Change (0), 1.0)
375 , _shift (X_("shift"), Change (0), 1.0)
376 , _read_data_count(0)
377 , _pending_changed(Change(0))
379 , _pending_explicit_relayer (false)
383 _sources.push_back (src);
385 if (set_state (node, Stateful::loading_state_version)) {
386 throw failed_constructor();
389 assert(_type != DataType::NIL);
390 assert(_sources.size() > 0);
395 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
399 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
402 _pending_changed = Change (0);
403 _read_data_count = 0;
404 _valid_transients = false;
407 _last_length = length;
408 _sync_position = other->_sync_position;
409 _ancestral_start = other->_ancestral_start;
410 _ancestral_length = other->_ancestral_length;
411 _stretch = other->_stretch;
412 _shift = other->_shift;
417 _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
418 _first_edit = EditChangesNothing;
420 _positional_lock_style = AudioTime;
422 use_sources (other->_sources);
426 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
428 _playlist = wpl.lock();
432 Region::set_name (const std::string& str)
435 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
436 assert(_name == str);
437 send_change (ARDOUR::NameChanged);
444 Region::set_length (nframes_t len, void */*src*/)
446 //cerr << "Region::set_length() len = " << len << endl;
447 if (_flags & Locked) {
451 if (_length != len && len != 0) {
453 /* check that the current _position wouldn't make the new
457 if (max_frames - len < _position) {
461 if (!verify_length (len)) {
466 _last_length = _length;
469 _flags = Region::Flag (_flags & ~WholeFile);
473 invalidate_transients ();
479 send_change (LengthChanged);
484 Region::maybe_uncopy ()
489 Region::first_edit ()
491 boost::shared_ptr<Playlist> pl (playlist());
493 if (_first_edit != EditChangesNothing && pl) {
495 _name = _session.new_region_name (_name);
496 _first_edit = EditChangesNothing;
498 send_change (ARDOUR::NameChanged);
499 RegionFactory::CheckNewRegion (shared_from_this());
504 Region::at_natural_position () const
506 boost::shared_ptr<Playlist> pl (playlist());
512 boost::shared_ptr<Region> whole_file_region = get_parent();
514 if (whole_file_region) {
515 if (_position == whole_file_region->position() + _start) {
524 Region::move_to_natural_position (void *src)
526 boost::shared_ptr<Playlist> pl (playlist());
532 boost::shared_ptr<Region> whole_file_region = get_parent();
534 if (whole_file_region) {
535 set_position (whole_file_region->position() + _start, src);
540 Region::special_set_position (nframes_t pos)
542 /* this is used when creating a whole file region as
543 a way to store its "natural" or "captured" position.
546 _position = _position;
551 Region::set_position_lock_style (PositionLockStyle ps)
553 boost::shared_ptr<Playlist> pl (playlist());
559 _positional_lock_style = ps;
561 if (_positional_lock_style == MusicTime) {
562 _session.tempo_map().bbt_time (_position, _bbt_time);
568 Region::update_position_after_tempo_map_change ()
570 boost::shared_ptr<Playlist> pl (playlist());
572 if (!pl || _positional_lock_style != MusicTime) {
576 TempoMap& map (_session.tempo_map());
577 nframes_t pos = map.frame_time (_bbt_time);
578 set_position_internal (pos, false);
582 Region::set_position (nframes_t pos, void* /*src*/)
588 set_position_internal (pos, true);
592 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
594 if (_position != pos) {
595 _last_position = _position;
598 /* check that the new _position wouldn't make the current
599 length impossible - if so, change the length.
601 XXX is this the right thing to do?
604 if (max_frames - _length < _position) {
605 _last_length = _length;
606 _length = max_frames - _position;
609 if (allow_bbt_recompute) {
610 recompute_position_from_lock_style ();
613 invalidate_transients ();
616 /* do this even if the position is the same. this helps out
617 a GUI that has moved its representation already.
620 send_change (PositionChanged);
624 Region::set_position_on_top (nframes_t pos, void* /*src*/)
626 if (_flags & Locked) {
630 if (_position != pos) {
631 _last_position = _position;
635 boost::shared_ptr<Playlist> pl (playlist());
638 pl->raise_region_to_top (shared_from_this ());
641 /* do this even if the position is the same. this helps out
642 a GUI that has moved its representation already.
645 send_change (PositionChanged);
649 Region::recompute_position_from_lock_style ()
651 if (_positional_lock_style == MusicTime) {
652 _session.tempo_map().bbt_time (_position, _bbt_time);
657 Region::nudge_position (nframes64_t n, void* /*src*/)
659 if (_flags & Locked) {
667 _last_position = _position;
670 if (_position > max_frames - n) {
671 _position = max_frames;
676 if (_position < (nframes_t) -n) {
683 send_change (PositionChanged);
687 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
689 _ancestral_length = l;
690 _ancestral_start = s;
696 Region::set_start (nframes_t pos, void* /*src*/)
698 if (_flags & (Locked|PositionLocked)) {
701 /* This just sets the start, nothing else. It effectively shifts
702 the contents of the Region within the overall extent of the Source,
703 without changing the Region's position or length
708 if (!verify_start (pos)) {
713 _flags = Region::Flag (_flags & ~WholeFile);
715 invalidate_transients ();
717 send_change (StartChanged);
722 Region::trim_start (nframes_t new_position, void */*src*/)
724 if (_flags & (Locked|PositionLocked)) {
730 if (new_position > _position) {
731 start_shift = new_position - _position;
733 start_shift = -(_position - new_position);
736 if (start_shift > 0) {
738 if (_start > max_frames - start_shift) {
739 new_start = max_frames;
741 new_start = _start + start_shift;
744 if (!verify_start (new_start)) {
748 } else if (start_shift < 0) {
750 if (_start < (nframes_t) -start_shift) {
753 new_start = _start + start_shift;
759 if (new_start == _start) {
764 _flags = Region::Flag (_flags & ~WholeFile);
767 send_change (StartChanged);
771 Region::trim_front (nframes_t new_position, void *src)
773 if (_flags & Locked) {
777 nframes_t end = last_frame();
778 nframes_t source_zero;
780 if (_position > _start) {
781 source_zero = _position - _start;
783 source_zero = 0; // its actually negative, but this will work for us
786 if (new_position < end) { /* can't trim it zero or negative length */
790 /* can't trim it back passed where source position zero is located */
792 new_position = max (new_position, source_zero);
795 if (new_position > _position) {
796 newlen = _length - (new_position - _position);
798 newlen = _length + (_position - new_position);
801 trim_to_internal (new_position, newlen, src);
803 recompute_at_start ();
808 /** @param new_endpoint New region end point, such that, for example,
809 * a region at 0 of length 10 has an endpoint of 9.
813 Region::trim_end (nframes_t new_endpoint, void */*src*/)
815 if (_flags & Locked) {
819 if (new_endpoint > _position) {
820 trim_to_internal (_position, new_endpoint - _position + 1, this);
828 Region::trim_to (nframes_t position, nframes_t length, void *src)
830 if (_flags & Locked) {
834 trim_to_internal (position, length, src);
837 recompute_at_start ();
843 Region::trim_to_internal (nframes_t position, nframes_t length, void */*src*/)
848 if (_flags & Locked) {
852 if (position > _position) {
853 start_shift = position - _position;
855 start_shift = -(_position - position);
858 if (start_shift > 0) {
860 if (_start > max_frames - start_shift) {
861 new_start = max_frames;
863 new_start = _start + start_shift;
867 } else if (start_shift < 0) {
869 if (_start < (nframes_t) -start_shift) {
872 new_start = _start + start_shift;
878 if (!verify_start_and_length (new_start, length)) {
882 Change what_changed = Change (0);
884 if (_start != new_start) {
886 what_changed = Change (what_changed|StartChanged);
888 if (_length != length) {
890 _last_length = _length;
893 what_changed = Change (what_changed|LengthChanged);
895 if (_position != position) {
897 _last_position = _position;
899 _position = position;
900 what_changed = Change (what_changed|PositionChanged);
903 _flags = Region::Flag (_flags & ~WholeFile);
905 if (what_changed & (StartChanged|LengthChanged)) {
910 send_change (what_changed);
915 Region::set_hidden (bool yn)
917 if (hidden() != yn) {
920 _flags = Flag (_flags|Hidden);
922 _flags = Flag (_flags & ~Hidden);
925 send_change (HiddenChanged);
930 Region::set_muted (bool yn)
935 _flags = Flag (_flags|Muted);
937 _flags = Flag (_flags & ~Muted);
940 send_change (MuteChanged);
945 Region::set_opaque (bool yn)
947 if (opaque() != yn) {
949 _flags = Flag (_flags|Opaque);
951 _flags = Flag (_flags & ~Opaque);
953 send_change (OpacityChanged);
958 Region::set_locked (bool yn)
960 if (locked() != yn) {
962 _flags = Flag (_flags|Locked);
964 _flags = Flag (_flags & ~Locked);
966 send_change (LockChanged);
971 Region::set_position_locked (bool yn)
973 if (position_locked() != yn) {
975 _flags = Flag (_flags|PositionLocked);
977 _flags = Flag (_flags & ~PositionLocked);
979 send_change (LockChanged);
984 Region::set_sync_position (nframes_t absolute_pos)
986 nframes_t const file_pos = _start + (absolute_pos - _position);
988 if (file_pos != _sync_position) {
990 _sync_position = file_pos;
991 _flags = Flag (_flags|SyncMarked);
996 send_change (SyncOffsetChanged);
1001 Region::clear_sync_position ()
1003 if (_flags & SyncMarked) {
1004 _flags = Flag (_flags & ~SyncMarked);
1009 send_change (SyncOffsetChanged);
1014 Region::sync_offset (int& dir) const
1016 /* returns the sync point relative the first frame of the region */
1018 if (_flags & SyncMarked) {
1019 if (_sync_position > _start) {
1021 return _sync_position - _start;
1024 return _start - _sync_position;
1033 Region::adjust_to_sync (nframes_t pos) const
1036 nframes_t offset = sync_offset (sync_dir);
1038 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1047 if (max_frames - pos > offset) {
1056 Region::sync_position() const
1058 if (_flags & SyncMarked) {
1059 return _sync_position;
1068 boost::shared_ptr<Playlist> pl (playlist());
1070 pl->raise_region (shared_from_this ());
1077 boost::shared_ptr<Playlist> pl (playlist());
1079 pl->lower_region (shared_from_this ());
1085 Region::raise_to_top ()
1087 boost::shared_ptr<Playlist> pl (playlist());
1089 pl->raise_region_to_top (shared_from_this());
1094 Region::lower_to_bottom ()
1096 boost::shared_ptr<Playlist> pl (playlist());
1098 pl->lower_region_to_bottom (shared_from_this());
1103 Region::set_layer (layer_t l)
1108 send_change (LayerChanged);
1113 Region::state (bool /*full_state*/)
1115 XMLNode *node = new XMLNode ("Region");
1117 const char* fe = NULL;
1121 _id.print (buf, sizeof (buf));
1122 node->add_property ("id", buf);
1123 node->add_property ("type", _type.to_string());
1125 switch (_first_edit) {
1126 case EditChangesNothing:
1129 case EditChangesName:
1135 default: /* should be unreachable but makes g++ happy */
1140 node->add_property ("first-edit", fe);
1142 /* note: flags are stored by derived classes */
1144 if (_positional_lock_style != AudioTime) {
1145 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1148 node->add_property ("bbt-position", str.str());
1155 Region::get_state ()
1157 return state (true);
1161 Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
1163 const XMLNodeList& nlist = node.children();
1164 const XMLProperty *prop;
1166 /* this is responsible for setting those aspects of Region state
1167 that are mutable after construction.
1170 if ((prop = node.property ("type")) == 0) {
1171 _type = DataType::AUDIO;
1173 _type = DataType(prop->value());
1176 if ((prop = node.property ("positional-lock-style")) != 0) {
1177 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1179 if (_positional_lock_style == MusicTime) {
1180 if ((prop = node.property ("bbt-position")) == 0) {
1181 /* missing BBT info, revert to audio time locking */
1182 _positional_lock_style = AudioTime;
1184 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1187 &_bbt_time.ticks) != 3) {
1188 _positional_lock_style = AudioTime;
1195 /* XXX FIRST EDIT !!! */
1197 /* fix problems with old sessions corrupted by impossible
1198 values for _stretch or _shift
1200 if (_stretch == 0.0f) {
1204 if (_shift == 0.0f) {
1208 /* note: derived classes set flags */
1210 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1216 if (child->name () == "Extra") {
1218 _extra_xml = new XMLNode (*child);
1224 cerr << _name << ": final change to be sent: " << hex << what_changed << dec << endl;
1225 send_change (what_changed);
1232 Region::set_state (const XMLNode& node, int version)
1234 const XMLProperty *prop;
1236 /* ID is not allowed to change, ever */
1238 if ((prop = node.property ("id"))) {
1239 _id = prop->value();
1242 _first_edit = EditChangesNothing;
1244 Change what_changed = set_state_using_states (node);
1246 set_live_state (node, version, what_changed, true);
1255 _last_length = _length;
1256 _last_position = _position;
1262 Change what_changed = Change (0);
1265 Glib::Mutex::Lock lm (_lock);
1267 if (_frozen && --_frozen > 0) {
1271 if (_pending_changed) {
1272 what_changed = _pending_changed;
1273 _pending_changed = Change (0);
1277 if (what_changed == Change (0)) {
1281 if (what_changed & LengthChanged) {
1282 if (what_changed & PositionChanged) {
1283 recompute_at_start ();
1285 recompute_at_end ();
1288 send_change (what_changed);
1292 Region::send_change (Change what_changed)
1296 Glib::Mutex::Lock lm (_lock);
1298 _pending_changed = Change (_pending_changed|what_changed);
1303 cerr << _name << " actually sends " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1304 StateChanged (what_changed);
1305 cerr << _name << " done with " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1307 if (!(_flags & DoNotSendPropertyChanges)) {
1309 /* Try and send a shared_pointer unless this is part of the constructor.
1314 boost::shared_ptr<Region> rptr = shared_from_this();
1315 cerr << _name << " actually sends prop change " << hex << what_changed << dec << " @ " << get_microseconds() << endl;
1316 RegionPropertyChanged (rptr);
1317 cerr << _name << " done with prop change @ " << get_microseconds() << endl;
1320 /* no shared_ptr available, relax; */
1327 Region::set_last_layer_op (uint64_t when)
1329 _last_layer_op = when;
1333 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1335 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1339 Region::equivalent (boost::shared_ptr<const Region> other) const
1341 return _start == other->_start &&
1342 _position == other->_position &&
1343 _length == other->_length;
1347 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1349 return _start == other->_start &&
1350 _length == other->_length;
1354 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1356 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1360 Region::source_deleted (boost::weak_ptr<Source>)
1364 if (!_session.deletion_in_progress()) {
1365 /* this is a very special case: at least one of the region's
1366 sources has bee deleted, so invalidate all references to
1367 ourselves. Do NOT do this during session deletion, because
1368 then we run the risk that this will actually result
1369 in this object being deleted (as refcnt goes to zero)
1370 while emitting DropReferences.
1378 Region::master_source_names ()
1380 SourceList::iterator i;
1382 vector<string> names;
1383 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1384 names.push_back((*i)->name());
1391 Region::set_master_sources (const SourceList& srcs)
1393 _master_sources = srcs;
1394 assert (_sources.size() == _master_sources.size());
1398 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1403 SourceList::const_iterator i;
1404 SourceList::const_iterator io;
1406 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1407 if ((*i)->id() != (*io)->id()) {
1412 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1413 if ((*i)->id() != (*io)->id()) {
1422 Region::uses_source (boost::shared_ptr<const Source> source) const
1424 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1433 Region::source_length(uint32_t n) const
1435 return _sources[n]->length(_position - _start);
1439 Region::verify_length (nframes_t len)
1441 if (source() && (source()->destructive() || source()->length_mutable())) {
1445 nframes_t maxlen = 0;
1447 for (uint32_t n=0; n < _sources.size(); ++n) {
1448 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1451 len = min (len, maxlen);
1457 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1459 if (source() && (source()->destructive() || source()->length_mutable())) {
1463 nframes_t maxlen = 0;
1465 for (uint32_t n=0; n < _sources.size(); ++n) {
1466 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1469 new_length = min (new_length, maxlen);
1475 Region::verify_start (nframes_t pos)
1477 if (source() && (source()->destructive() || source()->length_mutable())) {
1481 for (uint32_t n=0; n < _sources.size(); ++n) {
1482 if (pos > source_length(n) - _length) {
1490 Region::verify_start_mutable (nframes_t& new_start)
1492 if (source() && (source()->destructive() || source()->length_mutable())) {
1496 for (uint32_t n=0; n < _sources.size(); ++n) {
1497 if (new_start > source_length(n) - _length) {
1498 new_start = source_length(n) - _length;
1504 boost::shared_ptr<Region>
1505 Region::get_parent() const
1507 boost::shared_ptr<Playlist> pl (playlist());
1510 boost::shared_ptr<Region> r;
1511 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1513 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1514 return boost::static_pointer_cast<Region> (r);
1518 return boost::shared_ptr<Region>();
1522 Region::apply (Filter& filter)
1524 return filter.run (shared_from_this());
1529 Region::invalidate_transients ()
1531 _valid_transients = false;
1532 _transients.clear ();
1537 Region::use_sources (SourceList const & s)
1539 set<boost::shared_ptr<Source> > unique_srcs;
1541 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1542 _sources.push_back (*i);
1543 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1544 unique_srcs.insert (*i);
1547 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1548 _master_sources.push_back (*i);
1549 if (unique_srcs.find (*i) == unique_srcs.end()) {
1550 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));