2 Copyright (C) 2000-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <glibmm/thread.h>
27 #include "pbd/xml++.h"
28 #include "pbd/stacktrace.h"
29 #include "pbd/enumwriter.h"
31 #include "ardour/debug.h"
32 #include "ardour/file_source.h"
33 #include "ardour/filter.h"
34 #include "ardour/playlist.h"
35 #include "ardour/playlist_source.h"
36 #include "ardour/profile.h"
37 #include "ardour/region.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/session.h"
40 #include "ardour/source.h"
41 #include "ardour/source_factory.h"
42 #include "ardour/tempo.h"
43 #include "ardour/utils.h"
48 using namespace ARDOUR;
52 namespace Properties {
53 PBD::PropertyDescriptor<bool> muted;
54 PBD::PropertyDescriptor<bool> opaque;
55 PBD::PropertyDescriptor<bool> locked;
56 PBD::PropertyDescriptor<bool> automatic;
57 PBD::PropertyDescriptor<bool> whole_file;
58 PBD::PropertyDescriptor<bool> import;
59 PBD::PropertyDescriptor<bool> external;
60 PBD::PropertyDescriptor<bool> sync_marked;
61 PBD::PropertyDescriptor<bool> left_of_split;
62 PBD::PropertyDescriptor<bool> right_of_split;
63 PBD::PropertyDescriptor<bool> hidden;
64 PBD::PropertyDescriptor<bool> position_locked;
65 PBD::PropertyDescriptor<bool> valid_transients;
66 PBD::PropertyDescriptor<framepos_t> start;
67 PBD::PropertyDescriptor<framecnt_t> length;
68 PBD::PropertyDescriptor<framepos_t> position;
69 PBD::PropertyDescriptor<framecnt_t> sync_position;
70 PBD::PropertyDescriptor<layer_t> layer;
71 PBD::PropertyDescriptor<framepos_t> ancestral_start;
72 PBD::PropertyDescriptor<framecnt_t> ancestral_length;
73 PBD::PropertyDescriptor<float> stretch;
74 PBD::PropertyDescriptor<float> shift;
75 PBD::PropertyDescriptor<PositionLockStyle> position_lock_style;
76 PBD::PropertyDescriptor<uint64_t> layering_index;
80 PBD::Signal2<void,boost::shared_ptr<ARDOUR::Region>,const PropertyChange&> Region::RegionPropertyChanged;
83 Region::make_property_quarks ()
85 Properties::muted.property_id = g_quark_from_static_string (X_("muted"));
86 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id));
87 Properties::opaque.property_id = g_quark_from_static_string (X_("opaque"));
88 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id));
89 Properties::locked.property_id = g_quark_from_static_string (X_("locked"));
90 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id));
91 Properties::automatic.property_id = g_quark_from_static_string (X_("automatic"));
92 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id));
93 Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file"));
94 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id));
95 Properties::import.property_id = g_quark_from_static_string (X_("import"));
96 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id));
97 Properties::external.property_id = g_quark_from_static_string (X_("external"));
98 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id));
99 Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked"));
100 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id));
101 Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split"));
102 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id));
103 Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split"));
104 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id));
105 Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
106 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
107 Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
108 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id));
109 Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients"));
110 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n", Properties::valid_transients.property_id));
111 Properties::start.property_id = g_quark_from_static_string (X_("start"));
112 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id));
113 Properties::length.property_id = g_quark_from_static_string (X_("length"));
114 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id));
115 Properties::position.property_id = g_quark_from_static_string (X_("position"));
116 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id));
117 Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position"));
118 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id));
119 Properties::layer.property_id = g_quark_from_static_string (X_("layer"));
120 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id));
121 Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start"));
122 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id));
123 Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length"));
124 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id));
125 Properties::stretch.property_id = g_quark_from_static_string (X_("stretch"));
126 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id));
127 Properties::shift.property_id = g_quark_from_static_string (X_("shift"));
128 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id));
129 Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style"));
130 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id));
131 Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index"));
132 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n", Properties::layering_index.property_id));
136 Region::register_properties ()
138 _xml_node_name = X_("Region");
140 add_property (_muted);
141 add_property (_opaque);
142 add_property (_locked);
143 add_property (_automatic);
144 add_property (_whole_file);
145 add_property (_import);
146 add_property (_external);
147 add_property (_sync_marked);
148 add_property (_left_of_split);
149 add_property (_right_of_split);
150 add_property (_hidden);
151 add_property (_position_locked);
152 add_property (_valid_transients);
153 add_property (_start);
154 add_property (_length);
155 add_property (_position);
156 add_property (_sync_position);
157 add_property (_layer);
158 add_property (_ancestral_start);
159 add_property (_ancestral_length);
160 add_property (_stretch);
161 add_property (_shift);
162 add_property (_position_lock_style);
163 add_property (_layering_index);
166 #define REGION_DEFAULT_STATE(s,l) \
167 _sync_marked (Properties::sync_marked, false) \
168 , _left_of_split (Properties::left_of_split, false) \
169 , _right_of_split (Properties::right_of_split, false) \
170 , _valid_transients (Properties::valid_transients, false) \
171 , _start (Properties::start, (s)) \
172 , _length (Properties::length, (l)) \
173 , _position (Properties::position, 0) \
174 , _sync_position (Properties::sync_position, (s)) \
175 , _layer (Properties::layer, 0) \
176 , _muted (Properties::muted, false) \
177 , _opaque (Properties::opaque, true) \
178 , _locked (Properties::locked, false) \
179 , _automatic (Properties::automatic, false) \
180 , _whole_file (Properties::whole_file, false) \
181 , _import (Properties::import, false) \
182 , _external (Properties::external, false) \
183 , _hidden (Properties::hidden, false) \
184 , _position_locked (Properties::position_locked, false) \
185 , _ancestral_start (Properties::ancestral_start, (s)) \
186 , _ancestral_length (Properties::ancestral_length, (l)) \
187 , _stretch (Properties::stretch, 1.0) \
188 , _shift (Properties::shift, 1.0) \
189 , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \
190 , _layering_index (Properties::layering_index, 0)
192 #define REGION_COPY_STATE(other) \
193 _sync_marked (Properties::sync_marked, other->_sync_marked) \
194 , _left_of_split (Properties::left_of_split, other->_left_of_split) \
195 , _right_of_split (Properties::right_of_split, other->_right_of_split) \
196 , _valid_transients (Properties::valid_transients, other->_valid_transients) \
197 , _start(Properties::start, other->_start) \
198 , _length(Properties::length, other->_length) \
199 , _position(Properties::position, other->_position) \
200 , _sync_position(Properties::sync_position, other->_sync_position) \
201 , _layer (Properties::layer, other->_layer) \
202 , _muted (Properties::muted, other->_muted) \
203 , _opaque (Properties::opaque, other->_opaque) \
204 , _locked (Properties::locked, other->_locked) \
205 , _automatic (Properties::automatic, other->_automatic) \
206 , _whole_file (Properties::whole_file, other->_whole_file) \
207 , _import (Properties::import, other->_import) \
208 , _external (Properties::external, other->_external) \
209 , _hidden (Properties::hidden, other->_hidden) \
210 , _position_locked (Properties::position_locked, other->_position_locked) \
211 , _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \
212 , _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \
213 , _stretch (Properties::stretch, other->_stretch) \
214 , _shift (Properties::shift, other->_shift) \
215 , _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \
216 , _layering_index (Properties::layering_index, other->_layering_index)
218 /* derived-from-derived constructor (no sources in constructor) */
219 Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
220 : SessionObject(s, name)
222 , REGION_DEFAULT_STATE(start,length)
223 , _last_length (length)
225 , _first_edit (EditChangesNothing)
227 register_properties ();
229 /* no sources at this point */
232 /** Basic Region constructor (many sources) */
233 Region::Region (const SourceList& srcs)
234 : SessionObject(srcs.front()->session(), "toBeRenamed")
235 , _type (srcs.front()->type())
236 , REGION_DEFAULT_STATE(0,0)
239 , _first_edit (EditChangesNothing)
241 register_properties ();
243 _type = srcs.front()->type();
247 assert(_sources.size() > 0);
248 assert (_type == srcs.front()->type());
251 /** Create a new Region from an existing one */
252 Region::Region (boost::shared_ptr<const Region> other)
253 : SessionObject(other->session(), other->name())
254 , _type (other->data_type())
255 , REGION_COPY_STATE (other)
256 , _last_length (other->_last_length)
257 , _last_position(other->_last_position) \
258 , _first_edit (EditChangesNothing)
260 register_properties ();
262 /* override state that may have been incorrectly inherited from the other region
270 use_sources (other->_sources);
272 _position_lock_style = other->_position_lock_style;
273 _first_edit = other->_first_edit;
275 _start = 0; // It seems strange _start is not inherited here?
277 /* sync pos is relative to start of file. our start-in-file is now zero,
278 so set our sync position to whatever the the difference between
279 _start and _sync_pos was in the other region.
281 result is that our new sync pos points to the same point in our source(s)
282 as the sync in the other region did in its source(s).
284 since we start at zero in our source(s), it is not possible to use a sync point that
285 is before the start. reset it to _start if that was true in the other region.
288 if (other->sync_marked()) {
289 if (other->_start < other->_sync_position) {
290 /* sync pos was after the start point of the other region */
291 _sync_position = other->_sync_position - other->_start;
293 /* sync pos was before the start point of the other region. not possible here. */
294 _sync_marked = false;
295 _sync_position = _start;
298 _sync_marked = false;
299 _sync_position = _start;
302 if (Profile->get_sae()) {
303 /* reset sync point to start if its ended up
304 outside region bounds.
307 if (_sync_position < _start || _sync_position >= _start + _length) {
308 _sync_marked = false;
309 _sync_position = _start;
313 assert (_type == other->data_type());
316 /** Create a new Region from part of an existing one.
318 the start within \a other is given by \a offset
319 (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start()
321 Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset)
322 : SessionObject(other->session(), other->name())
323 , _type (other->data_type())
324 , REGION_COPY_STATE (other)
325 , _last_length (other->_last_length)
326 , _last_position(other->_last_position) \
327 , _first_edit (EditChangesNothing)
329 register_properties ();
331 /* override state that may have been incorrectly inherited from the other region
339 use_sources (other->_sources);
341 _start = other->_start + offset;
343 /* if the other region had a distinct sync point
344 set, then continue to use it as best we can.
345 otherwise, reset sync point back to start.
348 if (other->sync_marked()) {
349 if (other->_sync_position < _start) {
350 _sync_marked = false;
351 _sync_position = _start;
353 _sync_position = other->_sync_position;
356 _sync_marked = false;
357 _sync_position = _start;
360 if (Profile->get_sae()) {
361 /* reset sync point to start if its ended up
362 outside region bounds.
365 if (_sync_position < _start || _sync_position >= _start + _length) {
366 _sync_marked = false;
367 _sync_position = _start;
371 assert (_type == other->data_type());
374 /** Create a copy of @param other but with different sources. Used by filters */
375 Region::Region (boost::shared_ptr<const Region> other, const SourceList& srcs)
376 : SessionObject (other->session(), other->name())
377 , _type (srcs.front()->type())
378 , REGION_COPY_STATE (other)
379 , _last_length (other->_last_length)
380 , _last_position (other->_last_position)
381 , _first_edit (EditChangesID)
383 register_properties ();
386 _position_locked = false;
388 other->_first_edit = EditChangesName;
390 if (other->_extra_xml) {
391 _extra_xml = new XMLNode (*other->_extra_xml);
397 assert(_sources.size() > 0);
402 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
407 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
409 _playlist = wpl.lock();
413 Region::set_name (const std::string& str)
416 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
417 assert(_name == str);
419 send_change (Properties::name);
426 Region::set_length (framecnt_t len)
428 //cerr << "Region::set_length() len = " << len << endl;
433 if (_length != len && len != 0) {
435 /* check that the current _position wouldn't make the new
439 if (max_framepos - len < _position) {
443 if (!verify_length (len)) {
448 _last_length = _length;
449 set_length_internal (len);
453 invalidate_transients ();
455 if (!property_changes_suspended()) {
459 send_change (Properties::length);
464 Region::set_length_internal (framecnt_t len)
470 Region::maybe_uncopy ()
472 /* this does nothing but marked a semantic moment once upon a time */
476 Region::first_edit ()
478 boost::shared_ptr<Playlist> pl (playlist());
480 if (_first_edit != EditChangesNothing && pl) {
482 _name = RegionFactory::new_region_name (_name);
483 _first_edit = EditChangesNothing;
485 send_change (Properties::name);
487 RegionFactory::CheckNewRegion (shared_from_this());
492 Region::at_natural_position () const
494 boost::shared_ptr<Playlist> pl (playlist());
500 boost::shared_ptr<Region> whole_file_region = get_parent();
502 if (whole_file_region) {
503 if (_position == whole_file_region->position() + _start) {
512 Region::move_to_natural_position ()
514 boost::shared_ptr<Playlist> pl (playlist());
520 boost::shared_ptr<Region> whole_file_region = get_parent();
522 if (whole_file_region) {
523 set_position (whole_file_region->position() + _start);
528 Region::special_set_position (framepos_t pos)
530 /* this is used when creating a whole file region as
531 a way to store its "natural" or "captured" position.
534 _position = _position;
539 Region::set_position_lock_style (PositionLockStyle ps)
541 if (_position_lock_style != ps) {
543 boost::shared_ptr<Playlist> pl (playlist());
545 _position_lock_style = ps;
547 if (_position_lock_style == MusicTime) {
548 _session.tempo_map().bbt_time (_position, _bbt_time);
551 send_change (Properties::position_lock_style);
556 Region::update_after_tempo_map_change ()
558 boost::shared_ptr<Playlist> pl (playlist());
560 if (!pl || _position_lock_style != MusicTime) {
564 TempoMap& map (_session.tempo_map());
565 framepos_t pos = map.frame_time (_bbt_time);
566 set_position_internal (pos, false);
568 /* do this even if the position is the same. this helps out
569 a GUI that has moved its representation already.
571 send_change (Properties::position);
575 Region::set_position (framepos_t pos)
581 set_position_internal (pos, true);
583 /* do this even if the position is the same. this helps out
584 a GUI that has moved its representation already.
586 send_change (Properties::position);
591 Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
593 /* We emit a change of Properties::position even if the position hasn't changed
594 (see Region::set_position), so we must always set this up so that
595 e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
597 _last_position = _position;
599 if (_position != pos) {
602 /* check that the new _position wouldn't make the current
603 length impossible - if so, change the length.
605 XXX is this the right thing to do?
608 if (max_framepos - _length < _position) {
609 _last_length = _length;
610 _length = max_framepos - _position;
613 if (allow_bbt_recompute) {
614 recompute_position_from_lock_style ();
617 //invalidate_transients ();
622 Region::recompute_position_from_lock_style ()
624 if (_position_lock_style == MusicTime) {
625 _session.tempo_map().bbt_time (_position, _bbt_time);
630 Region::nudge_position (frameoffset_t n)
640 framepos_t new_position = _position;
643 if (_position > max_framepos - n) {
644 new_position = max_framepos;
649 if (_position < -n) {
656 set_position_internal (new_position, true);
658 send_change (Properties::position);
662 Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh)
664 _ancestral_length = l;
665 _ancestral_start = s;
671 Region::set_start (framepos_t pos)
673 if (locked() || position_locked()) {
676 /* This just sets the start, nothing else. It effectively shifts
677 the contents of the Region within the overall extent of the Source,
678 without changing the Region's position or length
683 if (!verify_start (pos)) {
690 invalidate_transients ();
692 send_change (Properties::start);
697 Region::trim_start (framepos_t new_position)
699 if (locked() || position_locked()) {
702 framepos_t new_start;
703 frameoffset_t const start_shift = new_position - _position;
705 if (start_shift > 0) {
707 if (_start > max_framepos - start_shift) {
708 new_start = max_framepos;
710 new_start = _start + start_shift;
713 if (!verify_start (new_start)) {
717 } else if (start_shift < 0) {
719 if (_start < -start_shift) {
722 new_start = _start + start_shift;
729 if (new_start == _start) {
737 send_change (Properties::start);
741 Region::trim_front (framepos_t new_position)
743 modify_front (new_position, false);
747 Region::cut_front (framepos_t new_position)
749 modify_front (new_position, true);
753 Region::cut_end (framepos_t new_endpoint)
755 modify_end (new_endpoint, true);
759 Region::modify_front (framepos_t new_position, bool reset_fade)
765 framepos_t end = last_frame();
766 framepos_t source_zero;
768 if (_position > _start) {
769 source_zero = _position - _start;
771 source_zero = 0; // its actually negative, but this will work for us
774 if (new_position < end) { /* can't trim it zero or negative length */
776 framecnt_t newlen = 0;
777 framepos_t delta = 0;
779 if (!can_trim_start_before_source_start ()) {
780 /* can't trim it back past where source position zero is located */
781 new_position = max (new_position, source_zero);
784 if (new_position > _position) {
785 newlen = _length - (new_position - _position);
786 delta = -1 * (new_position - _position);
788 newlen = _length + (_position - new_position);
789 delta = _position - new_position;
792 trim_to_internal (new_position, newlen);
795 _right_of_split = true;
798 if (!property_changes_suspended()) {
799 recompute_at_start ();
802 if (_transients.size() > 0){
803 adjust_transients(delta);
809 Region::modify_end (framepos_t new_endpoint, bool reset_fade)
815 if (new_endpoint > _position) {
816 trim_to_internal (_position, new_endpoint - _position);
818 _left_of_split = true;
820 if (!property_changes_suspended()) {
826 /** @param new_endpoint New region end point, such that, for example,
827 * a region at 0 of length 10 has an endpoint of 9.
831 Region::trim_end (framepos_t new_endpoint)
833 modify_end (new_endpoint, false);
837 Region::trim_to (framepos_t position, framecnt_t length)
843 trim_to_internal (position, length);
845 if (!property_changes_suspended()) {
846 recompute_at_start ();
852 Region::trim_to_internal (framepos_t position, framecnt_t length)
854 framepos_t new_start;
860 frameoffset_t const start_shift = position - _position;
862 if (start_shift > 0) {
864 if (_start > max_framepos - start_shift) {
865 new_start = max_framepos;
867 new_start = _start + start_shift;
870 } else if (start_shift < 0) {
872 if (_start < -start_shift && !can_trim_start_before_source_start ()) {
875 new_start = _start + start_shift;
882 if (!verify_start_and_length (new_start, length)) {
886 PropertyChange what_changed;
888 if (_start != new_start) {
890 what_changed.add (Properties::start);
893 /* Set position before length, otherwise for MIDI regions this bad thing happens:
894 * 1. we call set_length_internal; length in beats is computed using the region's current
895 * (soon-to-be old) position
896 * 2. we call set_position_internal; position is set and length in frames re-computed using
897 * length in beats from (1) but at the new position, which is wrong if the region
898 * straddles a tempo/meter change.
901 if (_position != position) {
902 if (!property_changes_suspended()) {
903 _last_position = _position;
905 set_position_internal (position, true);
906 what_changed.add (Properties::position);
909 if (_length != length) {
910 if (!property_changes_suspended()) {
911 _last_length = _length;
913 set_length_internal (length);
914 what_changed.add (Properties::length);
919 PropertyChange start_and_length;
921 start_and_length.add (Properties::start);
922 start_and_length.add (Properties::length);
924 if (what_changed.contains (start_and_length)) {
928 if (!what_changed.empty()) {
929 send_change (what_changed);
934 Region::set_hidden (bool yn)
936 if (hidden() != yn) {
938 send_change (Properties::hidden);
943 Region::set_whole_file (bool yn)
946 /* no change signal */
950 Region::set_automatic (bool yn)
953 /* no change signal */
957 Region::set_muted (bool yn)
961 send_change (Properties::muted);
966 Region::set_opaque (bool yn)
968 if (opaque() != yn) {
970 send_change (Properties::opaque);
975 Region::set_locked (bool yn)
977 if (locked() != yn) {
979 send_change (Properties::locked);
984 Region::set_position_locked (bool yn)
986 if (position_locked() != yn) {
987 _position_locked = yn;
988 send_change (Properties::locked);
992 /** Set the region's sync point.
993 * @param absolute_pos Session time.
996 Region::set_sync_position (framepos_t absolute_pos)
998 /* position within our file */
999 framepos_t const file_pos = _start + (absolute_pos - _position);
1001 if (file_pos != _sync_position) {
1002 _sync_marked = true;
1003 _sync_position = file_pos;
1004 if (!property_changes_suspended()) {
1008 send_change (Properties::sync_position);
1013 Region::clear_sync_position ()
1015 if (sync_marked()) {
1016 _sync_marked = false;
1017 if (!property_changes_suspended()) {
1021 send_change (Properties::sync_position);
1025 /* @return the sync point relative the first frame of the region */
1027 Region::sync_offset (int& dir) const
1029 if (sync_marked()) {
1030 if (_sync_position > _start) {
1032 return _sync_position - _start;
1035 return _start - _sync_position;
1044 Region::adjust_to_sync (framepos_t pos) const
1047 frameoffset_t offset = sync_offset (sync_dir);
1049 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1058 if (max_framepos - pos > offset) {
1066 /** @return Sync position in session time */
1068 Region::sync_position() const
1070 if (sync_marked()) {
1071 return _position - _start + _sync_position;
1073 /* if sync has not been marked, use the start of the region */
1081 boost::shared_ptr<Playlist> pl (playlist());
1083 pl->raise_region (shared_from_this ());
1090 boost::shared_ptr<Playlist> pl (playlist());
1092 pl->lower_region (shared_from_this ());
1098 Region::raise_to_top ()
1100 boost::shared_ptr<Playlist> pl (playlist());
1102 pl->raise_region_to_top (shared_from_this());
1107 Region::lower_to_bottom ()
1109 boost::shared_ptr<Playlist> pl (playlist());
1111 pl->lower_region_to_bottom (shared_from_this());
1116 Region::set_layer (layer_t l)
1121 send_change (Properties::layer);
1128 XMLNode *node = new XMLNode ("Region");
1131 LocaleGuard lg (X_("POSIX"));
1132 const char* fe = NULL;
1134 add_properties (*node);
1136 id().print (buf, sizeof (buf));
1137 node->add_property ("id", buf);
1138 node->add_property ("type", _type.to_string());
1140 switch (_first_edit) {
1141 case EditChangesNothing:
1144 case EditChangesName:
1150 default: /* should be unreachable but makes g++ happy */
1155 node->add_property ("first-edit", fe);
1157 /* note: flags are stored by derived classes */
1159 if (_position_lock_style != AudioTime) {
1162 node->add_property ("bbt-position", str.str());
1165 for (uint32_t n=0; n < _sources.size(); ++n) {
1166 snprintf (buf2, sizeof(buf2), "source-%d", n);
1167 _sources[n]->id().print (buf, sizeof(buf));
1168 node->add_property (buf2, buf);
1171 for (uint32_t n=0; n < _master_sources.size(); ++n) {
1172 snprintf (buf2, sizeof(buf2), "master-source-%d", n);
1173 _master_sources[n]->id().print (buf, sizeof (buf));
1174 node->add_property (buf2, buf);
1177 /* Only store nested sources for the whole-file region that acts
1178 as the parent/root of all regions using it.
1181 if (_whole_file && max_source_level() > 0) {
1183 XMLNode* nested_node = new XMLNode (X_("NestedSource"));
1185 /* region is compound - get its playlist and
1186 store that before we list the region that
1190 for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) {
1191 nested_node->add_child_nocopy ((*s)->get_state ());
1195 node->add_child_nocopy (*nested_node);
1200 node->add_child_copy (*_extra_xml);
1207 Region::get_state ()
1213 Region::set_state (const XMLNode& node, int version)
1215 PropertyChange what_changed;
1216 return _set_state (node, version, what_changed, true);
1220 Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
1222 const XMLProperty* prop;
1224 Stateful::save_extra_xml (node);
1226 what_changed = set_values (node);
1230 if (_position_lock_style == MusicTime) {
1231 if ((prop = node.property ("bbt-position")) == 0) {
1232 /* missing BBT info, revert to audio time locking */
1233 _position_lock_style = AudioTime;
1235 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1238 &_bbt_time.ticks) != 3) {
1239 _position_lock_style = AudioTime;
1244 /* fix problems with old sessions corrupted by impossible
1245 values for _stretch or _shift
1247 if (_stretch == 0.0f) {
1251 if (_shift == 0.0f) {
1256 send_change (what_changed);
1259 /* Quick fix for 2.x sessions when region is muted */
1260 if ((prop = node.property (X_("flags")))) {
1261 if (string::npos != prop->value().find("Muted")){
1271 Region::suspend_property_changes ()
1273 Stateful::suspend_property_changes ();
1274 _last_length = _length;
1275 _last_position = _position;
1279 Region::mid_thaw (const PropertyChange& what_changed)
1281 if (what_changed.contains (Properties::length)) {
1282 if (what_changed.contains (Properties::position)) {
1283 recompute_at_start ();
1285 recompute_at_end ();
1290 Region::send_change (const PropertyChange& what_changed)
1292 if (what_changed.empty()) {
1296 Stateful::send_change (what_changed);
1298 if (!Stateful::property_changes_suspended()) {
1300 /* Try and send a shared_pointer unless this is part of the constructor.
1305 boost::shared_ptr<Region> rptr = shared_from_this();
1306 RegionPropertyChanged (rptr, what_changed);
1308 /* no shared_ptr available, relax; */
1314 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1316 return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1320 Region::equivalent (boost::shared_ptr<const Region> other) const
1322 return _start == other->_start &&
1323 _position == other->_position &&
1324 _length == other->_length;
1328 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1330 return _start == other->_start &&
1331 _length == other->_length;
1335 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1337 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1341 Region::source_deleted (boost::weak_ptr<Source>)
1345 if (!_session.deletion_in_progress()) {
1346 /* this is a very special case: at least one of the region's
1347 sources has bee deleted, so invalidate all references to
1348 ourselves. Do NOT do this during session deletion, because
1349 then we run the risk that this will actually result
1350 in this object being deleted (as refcnt goes to zero)
1351 while emitting DropReferences.
1359 Region::master_source_names ()
1361 SourceList::iterator i;
1363 vector<string> names;
1364 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1365 names.push_back((*i)->name());
1372 Region::set_master_sources (const SourceList& srcs)
1374 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1375 (*i)->dec_use_count ();
1378 _master_sources = srcs;
1379 assert (_sources.size() == _master_sources.size());
1381 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1382 (*i)->inc_use_count ();
1387 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1392 if ((_sources.size() != other->_sources.size()) ||
1393 (_master_sources.size() != other->_master_sources.size())) {
1397 SourceList::const_iterator i;
1398 SourceList::const_iterator io;
1400 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1401 if ((*i)->id() != (*io)->id()) {
1406 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1407 if ((*i)->id() != (*io)->id()) {
1416 Region::source_string () const
1418 //string res = itos(_sources.size());
1421 res << _sources.size() << ":";
1423 SourceList::const_iterator i;
1425 for (i = _sources.begin(); i != _sources.end(); ++i) {
1426 res << (*i)->id() << ":";
1429 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1430 res << (*i)->id() << ":";
1437 Region::uses_source (boost::shared_ptr<const Source> source) const
1439 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1444 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1447 if (ps->playlist()->uses_source (source)) {
1457 Region::source_length(uint32_t n) const
1459 assert (n < _sources.size());
1460 return _sources[n]->length (_position - _start);
1464 Region::verify_length (framecnt_t len)
1466 if (source() && (source()->destructive() || source()->length_mutable())) {
1470 framecnt_t maxlen = 0;
1472 for (uint32_t n = 0; n < _sources.size(); ++n) {
1473 maxlen = max (maxlen, source_length(n) - _start);
1476 len = min (len, maxlen);
1482 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1484 if (source() && (source()->destructive() || source()->length_mutable())) {
1488 framecnt_t maxlen = 0;
1490 for (uint32_t n = 0; n < _sources.size(); ++n) {
1491 maxlen = max (maxlen, source_length(n) - new_start);
1494 new_length = min (new_length, maxlen);
1500 Region::verify_start (framepos_t pos)
1502 if (source() && (source()->destructive() || source()->length_mutable())) {
1506 for (uint32_t n = 0; n < _sources.size(); ++n) {
1507 if (pos > source_length(n) - _length) {
1515 Region::verify_start_mutable (framepos_t& new_start)
1517 if (source() && (source()->destructive() || source()->length_mutable())) {
1521 for (uint32_t n = 0; n < _sources.size(); ++n) {
1522 if (new_start > source_length(n) - _length) {
1523 new_start = source_length(n) - _length;
1529 boost::shared_ptr<Region>
1530 Region::get_parent() const
1532 boost::shared_ptr<Playlist> pl (playlist());
1535 boost::shared_ptr<Region> r;
1536 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1538 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1539 return boost::static_pointer_cast<Region> (r);
1543 return boost::shared_ptr<Region>();
1547 Region::apply (Filter& filter, Progress* progress)
1549 return filter.run (shared_from_this(), progress);
1554 Region::invalidate_transients ()
1556 _valid_transients = false;
1557 _transients.clear ();
1559 send_change (PropertyChange (Properties::valid_transients));
1563 Region::drop_sources ()
1565 for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1566 (*i)->dec_use_count ();
1571 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1572 (*i)->dec_use_count ();
1575 _master_sources.clear ();
1579 Region::use_sources (SourceList const & s)
1581 set<boost::shared_ptr<Source> > unique_srcs;
1583 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1585 _sources.push_back (*i);
1586 (*i)->inc_use_count ();
1587 _master_sources.push_back (*i);
1588 (*i)->inc_use_count ();
1590 /* connect only once to DropReferences, even if sources are replicated
1593 if (unique_srcs.find (*i) == unique_srcs.end ()) {
1594 unique_srcs.insert (*i);
1595 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1601 Region::can_trim () const
1603 CanTrim ct = CanTrim (0);
1609 /* if not locked, we can always move the front later, and the end earlier
1612 ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
1614 if (start() != 0 || can_trim_start_before_source_start ()) {
1615 ct = CanTrim (ct | FrontTrimEarlier);
1618 if (!_sources.empty()) {
1619 if ((start() + length()) < _sources.front()->length (0)) {
1620 ct = CanTrim (ct | EndTrimLater);
1628 Region::max_source_level () const
1632 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1633 lvl = max (lvl, (*i)->level());
1640 Region::is_compound () const
1642 return max_source_level() > 0;
1646 Region::post_set (const PropertyChange& pc)
1648 if (pc.contains (Properties::position)) {
1649 recompute_position_from_lock_style ();
1654 Region::set_pending_layer (double l)
1660 Region::reset_pending_layer ()
1662 bool const had = _pending_layer;
1663 _pending_layer = boost::optional<double> ();
1667 boost::optional<double>
1668 Region::pending_layer () const
1670 return _pending_layer;