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;
50 namespace Properties {
51 PBD::PropertyDescriptor<bool> muted;
52 PBD::PropertyDescriptor<bool> opaque;
53 PBD::PropertyDescriptor<bool> locked;
54 PBD::PropertyDescriptor<bool> automatic;
55 PBD::PropertyDescriptor<bool> whole_file;
56 PBD::PropertyDescriptor<bool> import;
57 PBD::PropertyDescriptor<bool> external;
58 PBD::PropertyDescriptor<bool> sync_marked;
59 PBD::PropertyDescriptor<bool> left_of_split;
60 PBD::PropertyDescriptor<bool> right_of_split;
61 PBD::PropertyDescriptor<bool> hidden;
62 PBD::PropertyDescriptor<bool> position_locked;
63 PBD::PropertyDescriptor<framepos_t> start;
64 PBD::PropertyDescriptor<framecnt_t> length;
65 PBD::PropertyDescriptor<framepos_t> position;
66 PBD::PropertyDescriptor<framecnt_t> sync_position;
67 PBD::PropertyDescriptor<layer_t> layer;
68 PBD::PropertyDescriptor<framepos_t> ancestral_start;
69 PBD::PropertyDescriptor<framecnt_t> ancestral_length;
70 PBD::PropertyDescriptor<float> stretch;
71 PBD::PropertyDescriptor<float> shift;
75 PBD::Signal2<void,boost::shared_ptr<ARDOUR::Region>,const PropertyChange&> Region::RegionPropertyChanged;
78 Region::make_property_quarks ()
80 Properties::muted.property_id = g_quark_from_static_string (X_("muted"));
81 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id));
82 Properties::opaque.property_id = g_quark_from_static_string (X_("opaque"));
83 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id));
84 Properties::locked.property_id = g_quark_from_static_string (X_("locked"));
85 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id));
86 Properties::automatic.property_id = g_quark_from_static_string (X_("automatic"));
87 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id));
88 Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file"));
89 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id));
90 Properties::import.property_id = g_quark_from_static_string (X_("import"));
91 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id));
92 Properties::external.property_id = g_quark_from_static_string (X_("external"));
93 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id));
94 Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked"));
95 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id));
96 Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split"));
97 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id));
98 Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split"));
99 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id));
100 Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
101 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
102 Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
103 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id));
104 Properties::start.property_id = g_quark_from_static_string (X_("start"));
105 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id));
106 Properties::length.property_id = g_quark_from_static_string (X_("length"));
107 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id));
108 Properties::position.property_id = g_quark_from_static_string (X_("position"));
109 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id));
110 Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position"));
111 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id));
112 Properties::layer.property_id = g_quark_from_static_string (X_("layer"));
113 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id));
114 Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start"));
115 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id));
116 Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length"));
117 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id));
118 Properties::stretch.property_id = g_quark_from_static_string (X_("stretch"));
119 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id));
120 Properties::shift.property_id = g_quark_from_static_string (X_("shift"));
121 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id));
125 Region::register_properties ()
127 _xml_node_name = X_("Region");
129 add_property (_muted);
130 add_property (_opaque);
131 add_property (_locked);
132 add_property (_automatic);
133 add_property (_whole_file);
134 add_property (_import);
135 add_property (_external);
136 add_property (_sync_marked);
137 add_property (_left_of_split);
138 add_property (_right_of_split);
139 add_property (_hidden);
140 add_property (_position_locked);
141 add_property (_start);
142 add_property (_length);
143 add_property (_position);
144 add_property (_sync_position);
145 add_property (_layer);
146 add_property (_ancestral_start);
147 add_property (_ancestral_length);
148 add_property (_stretch);
149 add_property (_shift);
152 #define REGION_DEFAULT_STATE(s,l) \
153 _muted (Properties::muted, false) \
154 , _opaque (Properties::opaque, true) \
155 , _locked (Properties::locked, false) \
156 , _automatic (Properties::automatic, false) \
157 , _whole_file (Properties::whole_file, false) \
158 , _import (Properties::import, false) \
159 , _external (Properties::external, false) \
160 , _sync_marked (Properties::sync_marked, false) \
161 , _left_of_split (Properties::left_of_split, false) \
162 , _right_of_split (Properties::right_of_split, false) \
163 , _hidden (Properties::hidden, false) \
164 , _position_locked (Properties::position_locked, false) \
165 , _start (Properties::start, (s)) \
166 , _length (Properties::length, (l)) \
167 , _position (Properties::position, 0) \
168 , _sync_position (Properties::sync_position, (s)) \
169 , _layer (Properties::layer, 0) \
170 , _ancestral_start (Properties::ancestral_start, (s)) \
171 , _ancestral_length (Properties::ancestral_length, (l)) \
172 , _stretch (Properties::stretch, 1.0) \
173 , _shift (Properties::shift, 1.0)
175 #define REGION_COPY_STATE(other) \
176 _muted (other->_muted) \
177 , _opaque (other->_opaque) \
178 , _locked (other->_locked) \
179 , _automatic (other->_automatic) \
180 , _whole_file (other->_whole_file) \
181 , _import (other->_import) \
182 , _external (other->_external) \
183 , _sync_marked (other->_sync_marked) \
184 , _left_of_split (other->_left_of_split) \
185 , _right_of_split (other->_right_of_split) \
186 , _hidden (other->_hidden) \
187 , _position_locked (other->_position_locked) \
188 , _start(other->_start) \
189 , _length(other->_length) \
190 , _position(other->_position) \
191 , _sync_position(other->_sync_position) \
192 , _layer (other->_layer) \
193 , _ancestral_start (other->_ancestral_start) \
194 , _ancestral_length (other->_ancestral_length) \
195 , _stretch (other->_stretch) \
196 , _shift (other->_shift)
198 /* derived-from-derived constructor (no sources in constructor) */
199 Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
200 : SessionObject(s, name)
202 , REGION_DEFAULT_STATE(start,length)
203 , _last_length (length)
205 , _positional_lock_style(AudioTime)
206 , _first_edit (EditChangesNothing)
207 , _read_data_count(0)
209 , _pending_explicit_relayer (false)
211 register_properties ();
213 /* no sources at this point */
216 /** Basic Region constructor (many sources) */
217 Region::Region (const SourceList& srcs)
218 : SessionObject(srcs.front()->session(), "toBeRenamed")
219 , _type (srcs.front()->type())
220 , REGION_DEFAULT_STATE(0,0)
223 , _positional_lock_style (_type == DataType::AUDIO ? AudioTime : MusicTime)
224 , _first_edit (EditChangesNothing)
225 , _valid_transients(false)
226 , _read_data_count(0)
228 , _pending_explicit_relayer (false)
230 register_properties ();
232 _type = srcs.front()->type();
236 assert(_sources.size() > 0);
237 assert (_type == srcs.front()->type());
240 /** Create a new Region from part of an existing one, starting at one of two places:
242 if @param offset_relative is true, then the start within @param other is given by @param offset
243 (i.e. relative to the start of @param other's sources, the start is @param offset + @param other.start()
245 if @param offset_relative is false, then the start within the source is given @param offset.
247 Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset, bool offset_relative)
248 : SessionObject(other->session(), other->name())
249 , _type (other->data_type())
250 , REGION_COPY_STATE (other)
251 , _last_length (other->_last_length)
252 , _last_position(other->_last_position) \
253 , _positional_lock_style(other->_positional_lock_style) \
254 , _first_edit (EditChangesNothing)
255 , _valid_transients(false)
256 , _read_data_count(0)
258 , _pending_explicit_relayer (false)
261 register_properties ();
263 /* override state that may have been incorrectly inherited from the other region
271 use_sources (other->_sources);
273 if (!offset_relative) {
275 /* not sure why we do this, but its a hangover from ardour before
276 property lists. this would be nice to remove.
279 _positional_lock_style = other->_positional_lock_style;
280 _first_edit = other->_first_edit;
286 /* sync pos is relative to start of file. our start-in-file is now zero,
287 so set our sync position to whatever the the difference between
288 _start and _sync_pos was in the other region.
290 result is that our new sync pos points to the same point in our source(s)
291 as the sync in the other region did in its source(s).
293 since we start at zero in our source(s), it is not possible to use a sync point that
294 is before the start. reset it to _start if that was true in the other region.
297 if (other->sync_marked()) {
298 if (other->_start < other->_sync_position) {
299 /* sync pos was after the start point of the other region */
300 _sync_position = other->_sync_position - other->_start;
302 /* sync pos was before the start point of the other region. not possible here. */
303 _sync_marked = false;
304 _sync_position = _start;
307 _sync_marked = false;
308 _sync_position = _start;
311 /* XXX do something else ! */
312 fatal << string_compose (_("programming error: %1"), X_("Region+offset constructor used with illegal combination of offset+relative"))
319 _start = other->_start + offset;
321 /* if the other region had a distinct sync point
322 set, then continue to use it as best we can.
323 otherwise, reset sync point back to start.
326 if (other->sync_marked()) {
327 if (other->_sync_position < _start) {
328 _sync_marked = false;
329 _sync_position = _start;
331 _sync_position = other->_sync_position;
334 _sync_marked = false;
335 _sync_position = _start;
339 if (Profile->get_sae()) {
340 /* reset sync point to start if its ended up
341 outside region bounds.
344 if (_sync_position < _start || _sync_position >= _start + _length) {
345 _sync_marked = false;
346 _sync_position = _start;
350 assert (_type == other->data_type());
353 /** Create a copy of @param other but with different sources. Used by filters */
354 Region::Region (boost::shared_ptr<const Region> other, const SourceList& srcs)
355 : SessionObject (other->session(), other->name())
356 , _type (srcs.front()->type())
357 , REGION_COPY_STATE (other)
358 , _last_length (other->_last_length)
359 , _last_position (other->_last_position)
360 , _positional_lock_style (other->_positional_lock_style)
361 , _first_edit (EditChangesID)
362 , _valid_transients (false)
363 , _read_data_count (0)
364 , _last_layer_op (other->_last_layer_op)
365 , _pending_explicit_relayer (false)
367 register_properties ();
370 _position_locked = false;
372 other->_first_edit = EditChangesName;
374 if (other->_extra_xml) {
375 _extra_xml = new XMLNode (*other->_extra_xml);
381 assert(_sources.size() > 0);
384 /** Simple "copy" constructor */
385 Region::Region (boost::shared_ptr<const Region> other)
386 : SessionObject(other->session(), other->name())
387 , _type(other->data_type())
388 , REGION_COPY_STATE (other)
389 , _last_length (other->_last_length)
390 , _last_position (other->_last_position)
391 , _positional_lock_style (other->_positional_lock_style)
392 , _first_edit (EditChangesID)
393 , _valid_transients(false)
394 , _read_data_count(0)
395 , _last_layer_op(other->_last_layer_op)
396 , _pending_explicit_relayer (false)
398 register_properties ();
401 _position_locked = false;
403 other->_first_edit = EditChangesName;
405 if (other->_extra_xml) {
406 _extra_xml = new XMLNode (*other->_extra_xml);
411 use_sources (other->_sources);
412 assert(_sources.size() > 0);
417 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
421 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
423 _playlist = wpl.lock();
427 Region::set_name (const std::string& str)
430 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
431 assert(_name == str);
432 send_change (Properties::name);
439 Region::set_length (framecnt_t len, void */*src*/)
441 //cerr << "Region::set_length() len = " << len << endl;
446 if (_length != len && len != 0) {
448 /* check that the current _position wouldn't make the new
452 if (max_frames - len < _position) {
456 if (!verify_length (len)) {
461 _last_length = _length;
466 invalidate_transients ();
468 if (!property_changes_suspended()) {
472 send_change (Properties::length);
477 Region::maybe_uncopy ()
479 /* this does nothing but marked a semantic moment once upon a time */
483 Region::first_edit ()
485 boost::shared_ptr<Playlist> pl (playlist());
487 if (_first_edit != EditChangesNothing && pl) {
489 _name = RegionFactory::new_region_name (_name);
490 _first_edit = EditChangesNothing;
492 send_change (Properties::name);
493 RegionFactory::CheckNewRegion (shared_from_this());
498 Region::at_natural_position () const
500 boost::shared_ptr<Playlist> pl (playlist());
506 boost::shared_ptr<Region> whole_file_region = get_parent();
508 if (whole_file_region) {
509 if (_position == whole_file_region->position() + _start) {
518 Region::move_to_natural_position (void *src)
520 boost::shared_ptr<Playlist> pl (playlist());
526 boost::shared_ptr<Region> whole_file_region = get_parent();
528 if (whole_file_region) {
529 set_position (whole_file_region->position() + _start, src);
534 Region::special_set_position (framepos_t pos)
536 /* this is used when creating a whole file region as
537 a way to store its "natural" or "captured" position.
540 _position = _position;
545 Region::set_position_lock_style (PositionLockStyle ps)
547 boost::shared_ptr<Playlist> pl (playlist());
553 _positional_lock_style = ps;
555 if (_positional_lock_style == MusicTime) {
556 _session.tempo_map().bbt_time (_position, _bbt_time);
562 Region::update_position_after_tempo_map_change ()
564 boost::shared_ptr<Playlist> pl (playlist());
566 if (!pl || _positional_lock_style != MusicTime) {
570 TempoMap& map (_session.tempo_map());
571 framepos_t pos = map.frame_time (_bbt_time);
572 set_position_internal (pos, false);
576 Region::set_position (framepos_t pos, void* /*src*/)
582 set_position_internal (pos, true);
586 Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
588 if (_position != pos) {
589 _last_position = _position;
592 /* check that the new _position wouldn't make the current
593 length impossible - if so, change the length.
595 XXX is this the right thing to do?
598 if (max_frames - _length < _position) {
599 _last_length = _length;
600 _length = max_frames - _position;
603 if (allow_bbt_recompute) {
604 recompute_position_from_lock_style ();
607 invalidate_transients ();
610 /* do this even if the position is the same. this helps out
611 a GUI that has moved its representation already.
614 send_change (Properties::position);
618 Region::set_position_on_top (framepos_t pos, void* /*src*/)
624 if (_position != pos) {
625 _last_position = _position;
629 boost::shared_ptr<Playlist> pl (playlist());
632 pl->raise_region_to_top (shared_from_this ());
635 /* do this even if the position is the same. this helps out
636 a GUI that has moved its representation already.
639 send_change (Properties::position);
643 Region::recompute_position_from_lock_style ()
645 if (_positional_lock_style == MusicTime) {
646 _session.tempo_map().bbt_time (_position, _bbt_time);
651 Region::nudge_position (frameoffset_t n, void* /*src*/)
661 _last_position = _position;
664 if (_position > max_frames - n) {
665 _position = max_frames;
670 if (_position < -n) {
677 send_change (Properties::position);
681 Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh)
683 _ancestral_length = l;
684 _ancestral_start = s;
690 Region::set_start (framepos_t pos, void* /*src*/)
692 if (locked() || position_locked()) {
695 /* This just sets the start, nothing else. It effectively shifts
696 the contents of the Region within the overall extent of the Source,
697 without changing the Region's position or length
702 if (!verify_start (pos)) {
709 invalidate_transients ();
711 send_change (Properties::start);
716 Region::trim_start (framepos_t new_position, void */*src*/)
718 if (locked() || position_locked()) {
721 framepos_t new_start;
722 frameoffset_t start_shift;
724 if (new_position > _position) {
725 start_shift = new_position - _position;
727 start_shift = -(_position - new_position);
730 if (start_shift > 0) {
732 if (_start > max_frames - start_shift) {
733 new_start = max_frames;
735 new_start = _start + start_shift;
738 if (!verify_start (new_start)) {
742 } else if (start_shift < 0) {
744 if (_start < -start_shift) {
747 new_start = _start + start_shift;
753 if (new_start == _start) {
761 send_change (Properties::start);
765 Region::trim_front (framepos_t new_position, void *src)
767 modify_front (new_position, false, src);
771 Region::cut_front (nframes_t new_position, void *src)
773 modify_front (new_position, true, src);
777 Region::cut_end (nframes_t new_endpoint, void *src)
779 modify_end (new_endpoint, true, src);
783 Region::modify_front (nframes_t new_position, bool reset_fade, void *src)
789 nframes_t end = last_frame();
790 nframes_t source_zero;
792 if (_position > _start) {
793 source_zero = _position - _start;
795 source_zero = 0; // its actually negative, but this will work for us
798 if (new_position < end) { /* can't trim it zero or negative length */
802 /* can't trim it back passed where source position zero is located */
804 new_position = max (new_position, source_zero);
806 if (new_position > _position) {
807 newlen = _length - (new_position - _position);
809 newlen = _length + (_position - new_position);
812 trim_to_internal (new_position, newlen, src);
814 _right_of_split = true;
817 if (!property_changes_suspended()) {
818 recompute_at_start ();
824 Region::modify_end (nframes_t new_endpoint, bool reset_fade, void *src)
830 if (new_endpoint > _position) {
831 trim_to_internal (_position, new_endpoint - _position +1, this);
833 _left_of_split = true;
835 if (!property_changes_suspended()) {
841 /** @param new_endpoint New region end point, such that, for example,
842 * a region at 0 of length 10 has an endpoint of 9.
846 Region::trim_end (framepos_t new_endpoint, void* src)
848 modify_end (new_endpoint, false, src);
852 Region::trim_to (framepos_t position, framecnt_t length, void *src)
858 trim_to_internal (position, length, src);
860 if (!property_changes_suspended()) {
861 recompute_at_start ();
867 Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/)
869 frameoffset_t start_shift;
870 framepos_t new_start;
876 if (position > _position) {
877 start_shift = position - _position;
879 start_shift = -(_position - position);
882 if (start_shift > 0) {
884 if (_start > max_frames - start_shift) {
885 new_start = max_frames;
887 new_start = _start + start_shift;
891 } else if (start_shift < 0) {
893 if (_start < -start_shift) {
896 new_start = _start + start_shift;
902 if (!verify_start_and_length (new_start, length)) {
906 PropertyChange what_changed;
908 if (_start != new_start) {
910 what_changed.add (Properties::start);
912 if (_length != length) {
913 if (!property_changes_suspended()) {
914 _last_length = _length;
917 what_changed.add (Properties::length);
919 if (_position != position) {
920 if (!property_changes_suspended()) {
921 _last_position = _position;
923 _position = position;
924 what_changed.add (Properties::position);
929 PropertyChange start_and_length;
931 start_and_length.add (Properties::start);
932 start_and_length.add (Properties::length);
934 if (what_changed.contains (start_and_length)) {
938 if (!what_changed.empty()) {
939 send_change (what_changed);
944 Region::set_hidden (bool yn)
946 if (hidden() != yn) {
948 send_change (Properties::hidden);
953 Region::set_whole_file (bool yn)
956 /* no change signal */
960 Region::set_automatic (bool yn)
963 /* no change signal */
967 Region::set_muted (bool yn)
971 send_change (Properties::muted);
976 Region::set_opaque (bool yn)
978 if (opaque() != yn) {
980 send_change (Properties::opaque);
985 Region::set_locked (bool yn)
987 if (locked() != yn) {
989 send_change (Properties::locked);
994 Region::set_position_locked (bool yn)
996 if (position_locked() != yn) {
997 _position_locked = yn;
998 send_change (Properties::locked);
1003 Region::set_sync_position (framepos_t absolute_pos)
1005 framepos_t const file_pos = _start + (absolute_pos - _position);
1007 if (file_pos != _sync_position) {
1008 _sync_marked = true;
1009 _sync_position = file_pos;
1010 if (!property_changes_suspended()) {
1013 send_change (Properties::sync_position);
1018 Region::clear_sync_position ()
1020 if (sync_marked()) {
1021 _sync_marked = false;
1022 if (!property_changes_suspended()) {
1025 send_change (Properties::sync_position);
1030 Region::sync_offset (int& dir) const
1032 /* returns the sync point relative the first frame of the region */
1034 if (sync_marked()) {
1035 if (_sync_position > _start) {
1037 return _sync_position - _start;
1040 return _start - _sync_position;
1049 Region::adjust_to_sync (framepos_t pos) const
1052 frameoffset_t offset = sync_offset (sync_dir);
1054 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1063 if (max_frames - pos > offset) {
1072 Region::sync_position() const
1074 if (sync_marked()) {
1075 return _sync_position;
1084 boost::shared_ptr<Playlist> pl (playlist());
1086 pl->raise_region (shared_from_this ());
1093 boost::shared_ptr<Playlist> pl (playlist());
1095 pl->lower_region (shared_from_this ());
1101 Region::raise_to_top ()
1103 boost::shared_ptr<Playlist> pl (playlist());
1105 pl->raise_region_to_top (shared_from_this());
1110 Region::lower_to_bottom ()
1112 boost::shared_ptr<Playlist> pl (playlist());
1114 pl->lower_region_to_bottom (shared_from_this());
1119 Region::set_layer (layer_t l)
1124 send_change (Properties::layer);
1129 Region::state (bool /*full_state*/)
1131 XMLNode *node = new XMLNode ("Region");
1133 const char* fe = NULL;
1135 add_properties (*node);
1137 _id.print (buf, sizeof (buf));
1138 node->add_property ("id", buf);
1139 node->add_property ("type", _type.to_string());
1141 switch (_first_edit) {
1142 case EditChangesNothing:
1145 case EditChangesName:
1151 default: /* should be unreachable but makes g++ happy */
1156 node->add_property ("first-edit", fe);
1158 /* note: flags are stored by derived classes */
1160 if (_positional_lock_style != AudioTime) {
1161 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1164 node->add_property ("bbt-position", str.str());
1171 Region::get_state ()
1173 return state (true);
1177 Region::set_state (const XMLNode& node, int version)
1179 PropertyChange what_changed;
1180 return _set_state (node, version, what_changed, true);
1184 Region::_set_state (const XMLNode& node, int version, PropertyChange& what_changed, bool send)
1186 const XMLProperty* prop;
1188 what_changed = set_properties (node);
1190 if ((prop = node.property (X_("id")))) {
1191 _id = prop->value();
1194 if ((prop = node.property ("positional-lock-style")) != 0) {
1195 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1197 if (_positional_lock_style == MusicTime) {
1198 if ((prop = node.property ("bbt-position")) == 0) {
1199 /* missing BBT info, revert to audio time locking */
1200 _positional_lock_style = AudioTime;
1202 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1205 &_bbt_time.ticks) != 3) {
1206 _positional_lock_style = AudioTime;
1213 /* fix problems with old sessions corrupted by impossible
1214 values for _stretch or _shift
1216 if (_stretch == 0.0f) {
1220 if (_shift == 0.0f) {
1224 const XMLNodeList& nlist = node.children();
1226 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1232 if (child->name () == "Extra") {
1234 _extra_xml = new XMLNode (*child);
1240 cerr << _name << ": final change to be sent: ";
1241 for (PropertyChange::iterator i = what_changed.begin(); i != what_changed.end(); ++i) {
1242 cerr << g_quark_to_string ((GQuark) *i) << ' ';
1245 send_change (what_changed);
1248 /* Quick fix for 2.x sessions when region is muted */
1249 if ((prop = node.property (X_("flags")))) {
1250 if (string::npos != prop->value().find("Muted")){
1260 Region::suspend_property_changes ()
1262 Stateful::suspend_property_changes ();
1263 _last_length = _length;
1264 _last_position = _position;
1268 Region::mid_thaw (const PropertyChange& what_changed)
1270 if (what_changed.contains (Properties::length)) {
1271 if (what_changed.contains (Properties::position)) {
1272 recompute_at_start ();
1274 recompute_at_end ();
1279 Region::send_change (const PropertyChange& what_changed)
1281 if (what_changed.empty()) {
1285 Stateful::send_change (what_changed);
1287 if (!_no_property_changes) {
1289 /* Try and send a shared_pointer unless this is part of the constructor.
1294 boost::shared_ptr<Region> rptr = shared_from_this();
1295 RegionPropertyChanged (rptr, what_changed);
1297 /* no shared_ptr available, relax; */
1303 Region::set_last_layer_op (uint64_t when)
1305 _last_layer_op = when;
1309 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1311 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1315 Region::equivalent (boost::shared_ptr<const Region> other) const
1317 return _start == other->_start &&
1318 _position == other->_position &&
1319 _length == other->_length;
1323 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1325 return _start == other->_start &&
1326 _length == other->_length;
1330 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1332 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1336 Region::source_deleted (boost::weak_ptr<Source>)
1340 if (!_session.deletion_in_progress()) {
1341 /* this is a very special case: at least one of the region's
1342 sources has bee deleted, so invalidate all references to
1343 ourselves. Do NOT do this during session deletion, because
1344 then we run the risk that this will actually result
1345 in this object being deleted (as refcnt goes to zero)
1346 while emitting DropReferences.
1354 Region::master_source_names ()
1356 SourceList::iterator i;
1358 vector<string> names;
1359 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1360 names.push_back((*i)->name());
1367 Region::set_master_sources (const SourceList& srcs)
1369 _master_sources = srcs;
1370 assert (_sources.size() == _master_sources.size());
1374 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1379 SourceList::const_iterator i;
1380 SourceList::const_iterator io;
1382 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1383 if ((*i)->id() != (*io)->id()) {
1388 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1389 if ((*i)->id() != (*io)->id()) {
1398 Region::uses_source (boost::shared_ptr<const Source> source) const
1400 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1409 Region::source_length(uint32_t n) const
1411 return _sources[n]->length(_position - _start);
1415 Region::verify_length (framecnt_t len)
1417 if (source() && (source()->destructive() || source()->length_mutable())) {
1421 framecnt_t maxlen = 0;
1423 for (uint32_t n=0; n < _sources.size(); ++n) {
1424 maxlen = max (maxlen, source_length(n) - _start);
1427 len = min (len, maxlen);
1433 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1435 if (source() && (source()->destructive() || source()->length_mutable())) {
1439 framecnt_t maxlen = 0;
1441 for (uint32_t n=0; n < _sources.size(); ++n) {
1442 maxlen = max (maxlen, source_length(n) - new_start);
1445 new_length = min (new_length, maxlen);
1451 Region::verify_start (framepos_t pos)
1453 if (source() && (source()->destructive() || source()->length_mutable())) {
1457 for (uint32_t n=0; n < _sources.size(); ++n) {
1458 if (pos > source_length(n) - _length) {
1466 Region::verify_start_mutable (framepos_t& new_start)
1468 if (source() && (source()->destructive() || source()->length_mutable())) {
1472 for (uint32_t n=0; n < _sources.size(); ++n) {
1473 if (new_start > source_length(n) - _length) {
1474 new_start = source_length(n) - _length;
1480 boost::shared_ptr<Region>
1481 Region::get_parent() const
1483 boost::shared_ptr<Playlist> pl (playlist());
1486 boost::shared_ptr<Region> r;
1487 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1489 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1490 return boost::static_pointer_cast<Region> (r);
1494 return boost::shared_ptr<Region>();
1498 Region::apply (Filter& filter)
1500 return filter.run (shared_from_this());
1505 Region::invalidate_transients ()
1507 _valid_transients = false;
1508 _transients.clear ();
1513 Region::use_sources (SourceList const & s)
1515 set<boost::shared_ptr<Source> > unique_srcs;
1517 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1518 _sources.push_back (*i);
1519 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1520 unique_srcs.insert (*i);
1523 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1524 _master_sources.push_back (*i);
1525 if (unique_srcs.find (*i) == unique_srcs.end()) {
1526 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1532 Region::property_factory (const XMLNode& history_node) const
1534 PropertyList* prop_list = new PropertyList;
1536 for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
1537 PropertyBase* prop = i->second->maybe_clone_self_if_found_in_history_node (history_node);
1540 prop_list->add (prop);