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 = _session.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);
1222 Region::suspend_property_changes ()
1224 Stateful::suspend_property_changes ();
1225 _last_length = _length;
1226 _last_position = _position;
1230 Region::mid_thaw (const PropertyChange& what_changed)
1232 if (what_changed.contains (Properties::length)) {
1233 if (what_changed.contains (Properties::position)) {
1234 recompute_at_start ();
1236 recompute_at_end ();
1241 Region::send_change (const PropertyChange& what_changed)
1243 if (what_changed.empty()) {
1247 Stateful::send_change (what_changed);
1249 if (!_no_property_changes) {
1251 /* Try and send a shared_pointer unless this is part of the constructor.
1256 boost::shared_ptr<Region> rptr = shared_from_this();
1257 RegionPropertyChanged (rptr, what_changed);
1259 /* no shared_ptr available, relax; */
1265 Region::set_last_layer_op (uint64_t when)
1267 _last_layer_op = when;
1271 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1273 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1277 Region::equivalent (boost::shared_ptr<const Region> other) const
1279 return _start == other->_start &&
1280 _position == other->_position &&
1281 _length == other->_length;
1285 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1287 return _start == other->_start &&
1288 _length == other->_length;
1292 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1294 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1298 Region::source_deleted (boost::weak_ptr<Source>)
1302 if (!_session.deletion_in_progress()) {
1303 /* this is a very special case: at least one of the region's
1304 sources has bee deleted, so invalidate all references to
1305 ourselves. Do NOT do this during session deletion, because
1306 then we run the risk that this will actually result
1307 in this object being deleted (as refcnt goes to zero)
1308 while emitting DropReferences.
1316 Region::master_source_names ()
1318 SourceList::iterator i;
1320 vector<string> names;
1321 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1322 names.push_back((*i)->name());
1329 Region::set_master_sources (const SourceList& srcs)
1331 _master_sources = srcs;
1332 assert (_sources.size() == _master_sources.size());
1336 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1341 SourceList::const_iterator i;
1342 SourceList::const_iterator io;
1344 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1345 if ((*i)->id() != (*io)->id()) {
1350 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1351 if ((*i)->id() != (*io)->id()) {
1360 Region::uses_source (boost::shared_ptr<const Source> source) const
1362 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1371 Region::source_length(uint32_t n) const
1373 return _sources[n]->length(_position - _start);
1377 Region::verify_length (framecnt_t len)
1379 if (source() && (source()->destructive() || source()->length_mutable())) {
1383 framecnt_t maxlen = 0;
1385 for (uint32_t n=0; n < _sources.size(); ++n) {
1386 maxlen = max (maxlen, source_length(n) - _start);
1389 len = min (len, maxlen);
1395 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1397 if (source() && (source()->destructive() || source()->length_mutable())) {
1401 framecnt_t maxlen = 0;
1403 for (uint32_t n=0; n < _sources.size(); ++n) {
1404 maxlen = max (maxlen, source_length(n) - new_start);
1407 new_length = min (new_length, maxlen);
1413 Region::verify_start (framepos_t pos)
1415 if (source() && (source()->destructive() || source()->length_mutable())) {
1419 for (uint32_t n=0; n < _sources.size(); ++n) {
1420 if (pos > source_length(n) - _length) {
1428 Region::verify_start_mutable (framepos_t& new_start)
1430 if (source() && (source()->destructive() || source()->length_mutable())) {
1434 for (uint32_t n=0; n < _sources.size(); ++n) {
1435 if (new_start > source_length(n) - _length) {
1436 new_start = source_length(n) - _length;
1442 boost::shared_ptr<Region>
1443 Region::get_parent() const
1445 boost::shared_ptr<Playlist> pl (playlist());
1448 boost::shared_ptr<Region> r;
1449 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1451 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1452 return boost::static_pointer_cast<Region> (r);
1456 return boost::shared_ptr<Region>();
1460 Region::apply (Filter& filter)
1462 return filter.run (shared_from_this());
1467 Region::invalidate_transients ()
1469 _valid_transients = false;
1470 _transients.clear ();
1475 Region::use_sources (SourceList const & s)
1477 set<boost::shared_ptr<Source> > unique_srcs;
1479 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1480 _sources.push_back (*i);
1481 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1482 unique_srcs.insert (*i);
1485 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1486 _master_sources.push_back (*i);
1487 if (unique_srcs.find (*i) == unique_srcs.end()) {
1488 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1495 Region::set_property (const PropertyBase& prop)
1497 DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 set property %2\n", _name.val(), prop.property_name()));
1499 if (prop == Properties::muted.property_id) {
1500 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1501 if (val != _muted) {
1502 DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 muted changed from %2 to %3",
1503 _name.val(), _muted.val(), val));
1507 } else if (prop == Properties::opaque.property_id) {
1508 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1509 if (val != _opaque) {
1510 DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 opaque changed from %2 to %3",
1511 _name.val(), _opaque.val(), val));
1515 } else if (prop == Properties::locked.property_id) {
1516 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1517 if (val != _locked) {
1518 DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 locked changed from %2 to %3",
1519 _name.val(), _locked.val(), val));
1523 } else if (prop == Properties::automatic.property_id) {
1524 _automatic = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1525 } else if (prop == Properties::whole_file.property_id) {
1526 _whole_file = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1527 } else if (prop == Properties::import.property_id) {
1528 _import = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1529 } else if (prop == Properties::external.property_id) {
1530 _external = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1531 } else if (prop == Properties::sync_marked.property_id) {
1532 _sync_marked = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1533 } else if (prop == Properties::left_of_split.property_id) {
1534 _left_of_split = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1535 } else if (prop == Properties::right_of_split.property_id) {
1536 _right_of_split = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1537 } else if (prop == Properties::hidden.property_id) {
1538 bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1539 if (val != _hidden) {
1543 } else if (prop == Properties::position_locked.property_id) {
1544 _position_locked = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
1545 } else if (prop == Properties::start.property_id) {
1546 framepos_t val = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
1547 if (val != _start) {
1548 DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 start changed from %2 to %3",
1549 _name.val(), _start, val));
1553 } else if (prop == Properties::length.property_id) {
1554 framecnt_t val = dynamic_cast<const PropertyTemplate<framecnt_t>* > (&prop)->val();
1555 if (val != _length) {
1556 DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 length changed from %2 to %3",
1557 _name.val(), _length, val));
1561 } else if (prop == Properties::position.property_id) {
1562 framepos_t val = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
1563 if (val != _position) {
1564 DEBUG_TRACE (DEBUG::Properties, string_compose ("region %1 position changed from %2 to %3",
1565 _name.val(), _position, val));
1569 } else if (prop == Properties::sync_position.property_id) {
1570 framepos_t val = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
1571 if (val != _sync_position) {
1572 _sync_position = val;
1575 } else if (prop == Properties::layer.property_id) {
1576 layer_t val = dynamic_cast<const PropertyTemplate<layer_t>*>(&prop)->val();
1577 if (val != _layer) {
1581 } else if (prop == Properties::ancestral_start.property_id) {
1582 _ancestral_start = dynamic_cast<const PropertyTemplate<framepos_t>*>(&prop)->val();
1583 } else if (prop == Properties::ancestral_length.property_id) {
1584 _ancestral_length = dynamic_cast<const PropertyTemplate<framecnt_t>*>(&prop)->val();
1585 } else if (prop == Properties::stretch.property_id) {
1586 _stretch = dynamic_cast<const PropertyTemplate<float>*>(&prop)->val();
1587 } else if (prop == Properties::shift.property_id) {
1588 _shift = dynamic_cast<const PropertyTemplate<float>*>(&prop)->val();
1590 return SessionObject::set_property (prop);
1597 Region::property_factory (const XMLNode& history_node) const
1599 PropertyList* prop_list = new PropertyList;
1601 for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
1602 PropertyBase* prop = i->second->maybe_clone_self_if_found_in_history_node (history_node);
1605 prop_list->add (prop);