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)
771 framepos_t end = last_frame();
772 framepos_t source_zero;
774 if (_position > _start) {
775 source_zero = _position - _start;
777 source_zero = 0; // its actually negative, but this will work for us
780 if (new_position < end) { /* can't trim it zero or negative length */
784 /* can't trim it back passed where source position zero is located */
786 new_position = max (new_position, source_zero);
789 if (new_position > _position) {
790 newlen = _length - (new_position - _position);
792 newlen = _length + (_position - new_position);
795 trim_to_internal (new_position, newlen, src);
796 if (!property_changes_suspended()) {
797 recompute_at_start ();
802 /** @param new_endpoint New region end point, such that, for example,
803 * a region at 0 of length 10 has an endpoint of 9.
807 Region::trim_end (framepos_t new_endpoint, void */*src*/)
813 if (new_endpoint > _position) {
814 trim_to_internal (_position, new_endpoint - _position + 1, this);
815 if (!property_changes_suspended()) {
822 Region::trim_to (framepos_t position, framecnt_t length, void *src)
828 trim_to_internal (position, length, src);
830 if (!property_changes_suspended()) {
831 recompute_at_start ();
837 Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/)
839 frameoffset_t start_shift;
840 framepos_t new_start;
846 if (position > _position) {
847 start_shift = position - _position;
849 start_shift = -(_position - position);
852 if (start_shift > 0) {
854 if (_start > max_frames - start_shift) {
855 new_start = max_frames;
857 new_start = _start + start_shift;
861 } else if (start_shift < 0) {
863 if (_start < -start_shift) {
866 new_start = _start + start_shift;
872 if (!verify_start_and_length (new_start, length)) {
876 PropertyChange what_changed;
878 if (_start != new_start) {
880 what_changed.add (Properties::start);
882 if (_length != length) {
883 if (!property_changes_suspended()) {
884 _last_length = _length;
887 what_changed.add (Properties::length);
889 if (_position != position) {
890 if (!property_changes_suspended()) {
891 _last_position = _position;
893 _position = position;
894 what_changed.add (Properties::position);
899 PropertyChange start_and_length;
901 start_and_length.add (Properties::start);
902 start_and_length.add (Properties::length);
904 if (what_changed.contains (start_and_length)) {
908 if (!what_changed.empty()) {
909 send_change (what_changed);
914 Region::set_hidden (bool yn)
916 if (hidden() != yn) {
918 send_change (Properties::hidden);
923 Region::set_whole_file (bool yn)
926 /* no change signal */
930 Region::set_automatic (bool yn)
933 /* no change signal */
937 Region::set_muted (bool yn)
941 send_change (Properties::muted);
946 Region::set_opaque (bool yn)
948 if (opaque() != yn) {
950 send_change (Properties::opaque);
955 Region::set_locked (bool yn)
957 if (locked() != yn) {
959 send_change (Properties::locked);
964 Region::set_position_locked (bool yn)
966 if (position_locked() != yn) {
967 _position_locked = yn;
968 send_change (Properties::locked);
973 Region::set_sync_position (framepos_t absolute_pos)
975 framepos_t const file_pos = _start + (absolute_pos - _position);
977 if (file_pos != _sync_position) {
979 _sync_position = file_pos;
980 if (!property_changes_suspended()) {
983 send_change (Properties::sync_position);
988 Region::clear_sync_position ()
991 _sync_marked = false;
992 if (!property_changes_suspended()) {
995 send_change (Properties::sync_position);
1000 Region::sync_offset (int& dir) const
1002 /* returns the sync point relative the first frame of the region */
1004 if (sync_marked()) {
1005 if (_sync_position > _start) {
1007 return _sync_position - _start;
1010 return _start - _sync_position;
1019 Region::adjust_to_sync (framepos_t pos) const
1022 frameoffset_t offset = sync_offset (sync_dir);
1024 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1033 if (max_frames - pos > offset) {
1042 Region::sync_position() const
1044 if (sync_marked()) {
1045 return _sync_position;
1054 boost::shared_ptr<Playlist> pl (playlist());
1056 pl->raise_region (shared_from_this ());
1063 boost::shared_ptr<Playlist> pl (playlist());
1065 pl->lower_region (shared_from_this ());
1071 Region::raise_to_top ()
1073 boost::shared_ptr<Playlist> pl (playlist());
1075 pl->raise_region_to_top (shared_from_this());
1080 Region::lower_to_bottom ()
1082 boost::shared_ptr<Playlist> pl (playlist());
1084 pl->lower_region_to_bottom (shared_from_this());
1089 Region::set_layer (layer_t l)
1094 send_change (Properties::layer);
1099 Region::state (bool /*full_state*/)
1101 XMLNode *node = new XMLNode ("Region");
1103 const char* fe = NULL;
1105 add_properties (*node);
1107 _id.print (buf, sizeof (buf));
1108 node->add_property ("id", buf);
1109 node->add_property ("type", _type.to_string());
1111 switch (_first_edit) {
1112 case EditChangesNothing:
1115 case EditChangesName:
1121 default: /* should be unreachable but makes g++ happy */
1126 node->add_property ("first-edit", fe);
1128 /* note: flags are stored by derived classes */
1130 if (_positional_lock_style != AudioTime) {
1131 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1134 node->add_property ("bbt-position", str.str());
1141 Region::get_state ()
1143 return state (true);
1147 Region::set_state (const XMLNode& node, int version)
1149 PropertyChange what_changed;
1150 return _set_state (node, version, what_changed, true);
1154 Region::_set_state (const XMLNode& node, int version, PropertyChange& what_changed, bool send)
1156 const XMLProperty* prop;
1158 what_changed = set_properties (node);
1160 if ((prop = node.property (X_("id")))) {
1161 _id = prop->value();
1164 if ((prop = node.property ("positional-lock-style")) != 0) {
1165 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1167 if (_positional_lock_style == MusicTime) {
1168 if ((prop = node.property ("bbt-position")) == 0) {
1169 /* missing BBT info, revert to audio time locking */
1170 _positional_lock_style = AudioTime;
1172 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1175 &_bbt_time.ticks) != 3) {
1176 _positional_lock_style = AudioTime;
1183 /* fix problems with old sessions corrupted by impossible
1184 values for _stretch or _shift
1186 if (_stretch == 0.0f) {
1190 if (_shift == 0.0f) {
1194 const XMLNodeList& nlist = node.children();
1196 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1202 if (child->name () == "Extra") {
1204 _extra_xml = new XMLNode (*child);
1210 cerr << _name << ": final change to be sent: ";
1211 for (PropertyChange::iterator i = what_changed.begin(); i != what_changed.end(); ++i) {
1212 cerr << g_quark_to_string ((GQuark) *i) << ' ';
1215 send_change (what_changed);
1218 /* Quick fix for 2.x sessions when region is muted */
1219 if ((prop = node.property (X_("flags")))) {
1220 if (string::npos != prop->value().find("Muted")){
1230 Region::suspend_property_changes ()
1232 Stateful::suspend_property_changes ();
1233 _last_length = _length;
1234 _last_position = _position;
1238 Region::mid_thaw (const PropertyChange& what_changed)
1240 if (what_changed.contains (Properties::length)) {
1241 if (what_changed.contains (Properties::position)) {
1242 recompute_at_start ();
1244 recompute_at_end ();
1249 Region::send_change (const PropertyChange& what_changed)
1251 if (what_changed.empty()) {
1255 Stateful::send_change (what_changed);
1257 if (!_no_property_changes) {
1259 /* Try and send a shared_pointer unless this is part of the constructor.
1264 boost::shared_ptr<Region> rptr = shared_from_this();
1265 RegionPropertyChanged (rptr, what_changed);
1267 /* no shared_ptr available, relax; */
1273 Region::set_last_layer_op (uint64_t when)
1275 _last_layer_op = when;
1279 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1281 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1285 Region::equivalent (boost::shared_ptr<const Region> other) const
1287 return _start == other->_start &&
1288 _position == other->_position &&
1289 _length == other->_length;
1293 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1295 return _start == other->_start &&
1296 _length == other->_length;
1300 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1302 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1306 Region::source_deleted (boost::weak_ptr<Source>)
1310 if (!_session.deletion_in_progress()) {
1311 /* this is a very special case: at least one of the region's
1312 sources has bee deleted, so invalidate all references to
1313 ourselves. Do NOT do this during session deletion, because
1314 then we run the risk that this will actually result
1315 in this object being deleted (as refcnt goes to zero)
1316 while emitting DropReferences.
1324 Region::master_source_names ()
1326 SourceList::iterator i;
1328 vector<string> names;
1329 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1330 names.push_back((*i)->name());
1337 Region::set_master_sources (const SourceList& srcs)
1339 _master_sources = srcs;
1340 assert (_sources.size() == _master_sources.size());
1344 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1349 SourceList::const_iterator i;
1350 SourceList::const_iterator io;
1352 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1353 if ((*i)->id() != (*io)->id()) {
1358 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1359 if ((*i)->id() != (*io)->id()) {
1368 Region::uses_source (boost::shared_ptr<const Source> source) const
1370 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1379 Region::source_length(uint32_t n) const
1381 return _sources[n]->length(_position - _start);
1385 Region::verify_length (framecnt_t len)
1387 if (source() && (source()->destructive() || source()->length_mutable())) {
1391 framecnt_t maxlen = 0;
1393 for (uint32_t n=0; n < _sources.size(); ++n) {
1394 maxlen = max (maxlen, source_length(n) - _start);
1397 len = min (len, maxlen);
1403 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1405 if (source() && (source()->destructive() || source()->length_mutable())) {
1409 framecnt_t maxlen = 0;
1411 for (uint32_t n=0; n < _sources.size(); ++n) {
1412 maxlen = max (maxlen, source_length(n) - new_start);
1415 new_length = min (new_length, maxlen);
1421 Region::verify_start (framepos_t pos)
1423 if (source() && (source()->destructive() || source()->length_mutable())) {
1427 for (uint32_t n=0; n < _sources.size(); ++n) {
1428 if (pos > source_length(n) - _length) {
1436 Region::verify_start_mutable (framepos_t& new_start)
1438 if (source() && (source()->destructive() || source()->length_mutable())) {
1442 for (uint32_t n=0; n < _sources.size(); ++n) {
1443 if (new_start > source_length(n) - _length) {
1444 new_start = source_length(n) - _length;
1450 boost::shared_ptr<Region>
1451 Region::get_parent() const
1453 boost::shared_ptr<Playlist> pl (playlist());
1456 boost::shared_ptr<Region> r;
1457 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1459 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1460 return boost::static_pointer_cast<Region> (r);
1464 return boost::shared_ptr<Region>();
1468 Region::apply (Filter& filter)
1470 return filter.run (shared_from_this());
1475 Region::invalidate_transients ()
1477 _valid_transients = false;
1478 _transients.clear ();
1483 Region::use_sources (SourceList const & s)
1485 set<boost::shared_ptr<Source> > unique_srcs;
1487 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1488 _sources.push_back (*i);
1489 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1490 unique_srcs.insert (*i);
1493 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1494 _master_sources.push_back (*i);
1495 if (unique_srcs.find (*i) == unique_srcs.end()) {
1496 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1502 Region::property_factory (const XMLNode& history_node) const
1504 PropertyList* prop_list = new PropertyList;
1506 for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
1507 PropertyBase* prop = i->second->maybe_clone_self_if_found_in_history_node (history_node);
1510 prop_list->add (prop);