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 (_ancestral_start);
158 add_property (_ancestral_length);
159 add_property (_stretch);
160 add_property (_shift);
161 add_property (_position_lock_style);
162 add_property (_layering_index);
165 #define REGION_DEFAULT_STATE(s,l) \
166 _sync_marked (Properties::sync_marked, false) \
167 , _left_of_split (Properties::left_of_split, false) \
168 , _right_of_split (Properties::right_of_split, false) \
169 , _valid_transients (Properties::valid_transients, false) \
170 , _start (Properties::start, (s)) \
171 , _length (Properties::length, (l)) \
172 , _position (Properties::position, 0) \
173 , _sync_position (Properties::sync_position, (s)) \
174 , _muted (Properties::muted, false) \
175 , _opaque (Properties::opaque, true) \
176 , _locked (Properties::locked, false) \
177 , _automatic (Properties::automatic, false) \
178 , _whole_file (Properties::whole_file, false) \
179 , _import (Properties::import, false) \
180 , _external (Properties::external, false) \
181 , _hidden (Properties::hidden, false) \
182 , _position_locked (Properties::position_locked, false) \
183 , _ancestral_start (Properties::ancestral_start, (s)) \
184 , _ancestral_length (Properties::ancestral_length, (l)) \
185 , _stretch (Properties::stretch, 1.0) \
186 , _shift (Properties::shift, 1.0) \
187 , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \
188 , _layering_index (Properties::layering_index, 0)
190 #define REGION_COPY_STATE(other) \
191 _sync_marked (Properties::sync_marked, other->_sync_marked) \
192 , _left_of_split (Properties::left_of_split, other->_left_of_split) \
193 , _right_of_split (Properties::right_of_split, other->_right_of_split) \
194 , _valid_transients (Properties::valid_transients, other->_valid_transients) \
195 , _start(Properties::start, other->_start) \
196 , _length(Properties::length, other->_length) \
197 , _position(Properties::position, other->_position) \
198 , _sync_position(Properties::sync_position, other->_sync_position) \
199 , _muted (Properties::muted, other->_muted) \
200 , _opaque (Properties::opaque, other->_opaque) \
201 , _locked (Properties::locked, other->_locked) \
202 , _automatic (Properties::automatic, other->_automatic) \
203 , _whole_file (Properties::whole_file, other->_whole_file) \
204 , _import (Properties::import, other->_import) \
205 , _external (Properties::external, other->_external) \
206 , _hidden (Properties::hidden, other->_hidden) \
207 , _position_locked (Properties::position_locked, other->_position_locked) \
208 , _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \
209 , _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \
210 , _stretch (Properties::stretch, other->_stretch) \
211 , _shift (Properties::shift, other->_shift) \
212 , _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \
213 , _layering_index (Properties::layering_index, other->_layering_index)
215 /* derived-from-derived constructor (no sources in constructor) */
216 Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
217 : SessionObject(s, name)
219 , REGION_DEFAULT_STATE(start,length)
220 , _last_length (length)
222 , _first_edit (EditChangesNothing)
225 register_properties ();
227 /* no sources at this point */
230 /** Basic Region constructor (many sources) */
231 Region::Region (const SourceList& srcs)
232 : SessionObject(srcs.front()->session(), "toBeRenamed")
233 , _type (srcs.front()->type())
234 , REGION_DEFAULT_STATE(0,0)
237 , _first_edit (EditChangesNothing)
240 register_properties ();
242 _type = srcs.front()->type();
246 assert(_sources.size() > 0);
247 assert (_type == srcs.front()->type());
250 /** Create a new Region from an existing one */
251 Region::Region (boost::shared_ptr<const Region> other)
252 : SessionObject(other->session(), other->name())
253 , _type (other->data_type())
254 , REGION_COPY_STATE (other)
255 , _last_length (other->_last_length)
256 , _last_position(other->_last_position) \
257 , _first_edit (EditChangesNothing)
258 , _layer (other->_layer)
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)
328 , _layer (other->_layer)
330 register_properties ();
332 /* override state that may have been incorrectly inherited from the other region
340 use_sources (other->_sources);
342 _start = other->_start + offset;
344 /* if the other region had a distinct sync point
345 set, then continue to use it as best we can.
346 otherwise, reset sync point back to start.
349 if (other->sync_marked()) {
350 if (other->_sync_position < _start) {
351 _sync_marked = false;
352 _sync_position = _start;
354 _sync_position = other->_sync_position;
357 _sync_marked = false;
358 _sync_position = _start;
361 if (Profile->get_sae()) {
362 /* reset sync point to start if its ended up
363 outside region bounds.
366 if (_sync_position < _start || _sync_position >= _start + _length) {
367 _sync_marked = false;
368 _sync_position = _start;
372 assert (_type == other->data_type());
375 /** Create a copy of @param other but with different sources. Used by filters */
376 Region::Region (boost::shared_ptr<const Region> other, const SourceList& srcs)
377 : SessionObject (other->session(), other->name())
378 , _type (srcs.front()->type())
379 , REGION_COPY_STATE (other)
380 , _last_length (other->_last_length)
381 , _last_position (other->_last_position)
382 , _first_edit (EditChangesID)
383 , _layer (other->_layer)
385 register_properties ();
388 _position_locked = false;
390 other->_first_edit = EditChangesName;
392 if (other->_extra_xml) {
393 _extra_xml = new XMLNode (*other->_extra_xml);
399 assert(_sources.size() > 0);
404 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
409 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
411 _playlist = wpl.lock();
415 Region::set_name (const std::string& str)
418 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
419 assert(_name == str);
421 send_change (Properties::name);
428 Region::set_length (framecnt_t len)
430 //cerr << "Region::set_length() len = " << len << endl;
435 if (_length != len && len != 0) {
437 /* check that the current _position wouldn't make the new
441 if (max_framepos - len < _position) {
445 if (!verify_length (len)) {
450 _last_length = _length;
451 set_length_internal (len);
455 invalidate_transients ();
457 if (!property_changes_suspended()) {
461 send_change (Properties::length);
466 Region::set_length_internal (framecnt_t len)
472 Region::maybe_uncopy ()
474 /* this does nothing but marked a semantic moment once upon a time */
478 Region::first_edit ()
480 boost::shared_ptr<Playlist> pl (playlist());
482 if (_first_edit != EditChangesNothing && pl) {
484 _name = RegionFactory::new_region_name (_name);
485 _first_edit = EditChangesNothing;
487 send_change (Properties::name);
489 RegionFactory::CheckNewRegion (shared_from_this());
494 Region::at_natural_position () const
496 boost::shared_ptr<Playlist> pl (playlist());
502 boost::shared_ptr<Region> whole_file_region = get_parent();
504 if (whole_file_region) {
505 if (_position == whole_file_region->position() + _start) {
514 Region::move_to_natural_position ()
516 boost::shared_ptr<Playlist> pl (playlist());
522 boost::shared_ptr<Region> whole_file_region = get_parent();
524 if (whole_file_region) {
525 set_position (whole_file_region->position() + _start);
530 Region::special_set_position (framepos_t pos)
532 /* this is used when creating a whole file region as
533 a way to store its "natural" or "captured" position.
536 _position = _position;
541 Region::set_position_lock_style (PositionLockStyle ps)
543 if (_position_lock_style != ps) {
545 boost::shared_ptr<Playlist> pl (playlist());
547 _position_lock_style = ps;
549 if (_position_lock_style == MusicTime) {
550 _session.bbt_time (_position, _bbt_time);
553 send_change (Properties::position_lock_style);
558 Region::update_after_tempo_map_change ()
560 boost::shared_ptr<Playlist> pl (playlist());
562 if (!pl || _position_lock_style != MusicTime) {
566 TempoMap& map (_session.tempo_map());
567 framepos_t pos = map.frame_time (_bbt_time);
568 set_position_internal (pos, false);
570 /* do this even if the position is the same. this helps out
571 a GUI that has moved its representation already.
573 send_change (Properties::position);
577 Region::set_position (framepos_t pos)
583 set_position_internal (pos, true);
585 /* do this even if the position is the same. this helps out
586 a GUI that has moved its representation already.
588 send_change (Properties::position);
593 Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
595 /* We emit a change of Properties::position even if the position hasn't changed
596 (see Region::set_position), so we must always set this up so that
597 e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
599 _last_position = _position;
601 if (_position != pos) {
604 /* check that the new _position wouldn't make the current
605 length impossible - if so, change the length.
607 XXX is this the right thing to do?
610 if (max_framepos - _length < _position) {
611 _last_length = _length;
612 _length = max_framepos - _position;
615 if (allow_bbt_recompute) {
616 recompute_position_from_lock_style ();
619 //invalidate_transients ();
624 Region::recompute_position_from_lock_style ()
626 if (_position_lock_style == MusicTime) {
627 _session.bbt_time (_position, _bbt_time);
632 Region::nudge_position (frameoffset_t n)
642 framepos_t new_position = _position;
645 if (_position > max_framepos - n) {
646 new_position = max_framepos;
651 if (_position < -n) {
658 set_position_internal (new_position, true);
660 send_change (Properties::position);
664 Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh)
666 _ancestral_length = l;
667 _ancestral_start = s;
673 Region::set_start (framepos_t pos)
675 if (locked() || position_locked()) {
678 /* This just sets the start, nothing else. It effectively shifts
679 the contents of the Region within the overall extent of the Source,
680 without changing the Region's position or length
685 if (!verify_start (pos)) {
689 set_start_internal (pos);
692 invalidate_transients ();
694 send_change (Properties::start);
699 Region::trim_start (framepos_t new_position)
701 if (locked() || position_locked()) {
705 framepos_t new_start;
706 frameoffset_t const start_shift = new_position - _position;
708 if (start_shift > 0) {
710 if (_start > max_framepos - start_shift) {
711 new_start = max_framepos;
713 new_start = _start + start_shift;
716 if (!verify_start (new_start)) {
720 } else if (start_shift < 0) {
722 if (_start < -start_shift) {
725 new_start = _start + start_shift;
732 if (new_start == _start) {
736 set_start_internal (new_start);
740 send_change (Properties::start);
744 Region::trim_front (framepos_t new_position)
746 modify_front (new_position, false);
750 Region::cut_front (framepos_t new_position)
752 modify_front (new_position, true);
756 Region::cut_end (framepos_t new_endpoint)
758 modify_end (new_endpoint, true);
762 Region::modify_front (framepos_t new_position, bool reset_fade)
768 framepos_t end = last_frame();
769 framepos_t source_zero;
771 if (_position > _start) {
772 source_zero = _position - _start;
774 source_zero = 0; // its actually negative, but this will work for us
777 if (new_position < end) { /* can't trim it zero or negative length */
779 framecnt_t newlen = 0;
780 framepos_t delta = 0;
782 if (!can_trim_start_before_source_start ()) {
783 /* can't trim it back past where source position zero is located */
784 new_position = max (new_position, source_zero);
787 if (new_position > _position) {
788 newlen = _length - (new_position - _position);
789 delta = -1 * (new_position - _position);
791 newlen = _length + (_position - new_position);
792 delta = _position - new_position;
795 trim_to_internal (new_position, newlen);
798 _right_of_split = true;
801 if (!property_changes_suspended()) {
802 recompute_at_start ();
805 if (_transients.size() > 0){
806 adjust_transients(delta);
812 Region::modify_end (framepos_t new_endpoint, bool reset_fade)
818 if (new_endpoint > _position) {
819 trim_to_internal (_position, new_endpoint - _position);
821 _left_of_split = true;
823 if (!property_changes_suspended()) {
829 /** @param new_endpoint New region end point, such that, for example,
830 * a region at 0 of length 10 has an endpoint of 9.
834 Region::trim_end (framepos_t new_endpoint)
836 modify_end (new_endpoint, false);
840 Region::trim_to (framepos_t position, framecnt_t length)
846 trim_to_internal (position, length);
848 if (!property_changes_suspended()) {
849 recompute_at_start ();
855 Region::trim_to_internal (framepos_t position, framecnt_t length)
857 framepos_t new_start;
863 frameoffset_t const start_shift = position - _position;
865 if (start_shift > 0) {
867 if (_start > max_framepos - start_shift) {
868 new_start = max_framepos;
870 new_start = _start + start_shift;
873 } else if (start_shift < 0) {
875 if (_start < -start_shift && !can_trim_start_before_source_start ()) {
878 new_start = _start + start_shift;
885 if (!verify_start_and_length (new_start, length)) {
889 PropertyChange what_changed;
891 if (_start != new_start) {
892 set_start_internal (new_start);
893 what_changed.add (Properties::start);
896 /* Set position before length, otherwise for MIDI regions this bad thing happens:
897 * 1. we call set_length_internal; length in beats is computed using the region's current
898 * (soon-to-be old) position
899 * 2. we call set_position_internal; position is set and length in frames re-computed using
900 * length in beats from (1) but at the new position, which is wrong if the region
901 * straddles a tempo/meter change.
904 if (_position != position) {
905 if (!property_changes_suspended()) {
906 _last_position = _position;
908 set_position_internal (position, true);
909 what_changed.add (Properties::position);
912 if (_length != length) {
913 if (!property_changes_suspended()) {
914 _last_length = _length;
916 set_length_internal (length);
917 what_changed.add (Properties::length);
922 PropertyChange start_and_length;
924 start_and_length.add (Properties::start);
925 start_and_length.add (Properties::length);
927 if (what_changed.contains (start_and_length)) {
931 if (!what_changed.empty()) {
932 send_change (what_changed);
937 Region::set_hidden (bool yn)
939 if (hidden() != yn) {
941 send_change (Properties::hidden);
946 Region::set_whole_file (bool yn)
949 /* no change signal */
953 Region::set_automatic (bool yn)
956 /* no change signal */
960 Region::set_muted (bool yn)
964 send_change (Properties::muted);
969 Region::set_opaque (bool yn)
971 if (opaque() != yn) {
973 send_change (Properties::opaque);
978 Region::set_locked (bool yn)
980 if (locked() != yn) {
982 send_change (Properties::locked);
987 Region::set_position_locked (bool yn)
989 if (position_locked() != yn) {
990 _position_locked = yn;
991 send_change (Properties::locked);
995 /** Set the region's sync point.
996 * @param absolute_pos Session time.
999 Region::set_sync_position (framepos_t absolute_pos)
1001 /* position within our file */
1002 framepos_t const file_pos = _start + (absolute_pos - _position);
1004 if (file_pos != _sync_position) {
1005 _sync_marked = true;
1006 _sync_position = file_pos;
1007 if (!property_changes_suspended()) {
1011 send_change (Properties::sync_position);
1016 Region::clear_sync_position ()
1018 if (sync_marked()) {
1019 _sync_marked = false;
1020 if (!property_changes_suspended()) {
1024 send_change (Properties::sync_position);
1028 /* @return the sync point relative the first frame of the region */
1030 Region::sync_offset (int& dir) const
1032 if (sync_marked()) {
1033 if (_sync_position > _start) {
1035 return _sync_position - _start;
1038 return _start - _sync_position;
1047 Region::adjust_to_sync (framepos_t pos) const
1050 frameoffset_t offset = sync_offset (sync_dir);
1052 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1061 if (max_framepos - pos > offset) {
1069 /** @return Sync position in session time */
1071 Region::sync_position() const
1073 if (sync_marked()) {
1074 return _position - _start + _sync_position;
1076 /* if sync has not been marked, use the start of the region */
1084 boost::shared_ptr<Playlist> pl (playlist());
1086 pl->raise_region (shared_from_this ());
1093 boost::shared_ptr<Playlist> pl (playlist());
1095 pl->lower_region (shared_from_this ());
1101 Region::raise_to_top ()
1103 boost::shared_ptr<Playlist> pl (playlist());
1105 pl->raise_region_to_top (shared_from_this());
1110 Region::lower_to_bottom ()
1112 boost::shared_ptr<Playlist> pl (playlist());
1114 pl->lower_region_to_bottom (shared_from_this());
1119 Region::set_layer (layer_t l)
1127 XMLNode *node = new XMLNode ("Region");
1130 LocaleGuard lg (X_("POSIX"));
1131 const char* fe = NULL;
1133 add_properties (*node);
1135 id().print (buf, sizeof (buf));
1136 node->add_property ("id", buf);
1137 node->add_property ("type", _type.to_string());
1139 switch (_first_edit) {
1140 case EditChangesNothing:
1143 case EditChangesName:
1149 default: /* should be unreachable but makes g++ happy */
1154 node->add_property ("first-edit", fe);
1156 /* note: flags are stored by derived classes */
1158 if (_position_lock_style != AudioTime) {
1161 node->add_property ("bbt-position", str.str());
1164 for (uint32_t n=0; n < _sources.size(); ++n) {
1165 snprintf (buf2, sizeof(buf2), "source-%d", n);
1166 _sources[n]->id().print (buf, sizeof(buf));
1167 node->add_property (buf2, buf);
1170 for (uint32_t n=0; n < _master_sources.size(); ++n) {
1171 snprintf (buf2, sizeof(buf2), "master-source-%d", n);
1172 _master_sources[n]->id().print (buf, sizeof (buf));
1173 node->add_property (buf2, buf);
1176 /* Only store nested sources for the whole-file region that acts
1177 as the parent/root of all regions using it.
1180 if (_whole_file && max_source_level() > 0) {
1182 XMLNode* nested_node = new XMLNode (X_("NestedSource"));
1184 /* region is compound - get its playlist and
1185 store that before we list the region that
1189 for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) {
1190 nested_node->add_child_nocopy ((*s)->get_state ());
1194 node->add_child_nocopy (*nested_node);
1199 node->add_child_copy (*_extra_xml);
1206 Region::get_state ()
1212 Region::set_state (const XMLNode& node, int version)
1214 PropertyChange what_changed;
1215 return _set_state (node, version, what_changed, true);
1219 Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
1221 const XMLProperty* prop;
1223 Stateful::save_extra_xml (node);
1225 what_changed = set_values (node);
1229 if (_position_lock_style == MusicTime) {
1230 if ((prop = node.property ("bbt-position")) == 0) {
1231 /* missing BBT info, revert to audio time locking */
1232 _position_lock_style = AudioTime;
1234 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1237 &_bbt_time.ticks) != 3) {
1238 _position_lock_style = AudioTime;
1243 /* fix problems with old sessions corrupted by impossible
1244 values for _stretch or _shift
1246 if (_stretch == 0.0f) {
1250 if (_shift == 0.0f) {
1255 send_change (what_changed);
1258 /* Quick fix for 2.x sessions when region is muted */
1259 if ((prop = node.property (X_("flags")))) {
1260 if (string::npos != prop->value().find("Muted")){
1270 Region::suspend_property_changes ()
1272 Stateful::suspend_property_changes ();
1273 _last_length = _length;
1274 _last_position = _position;
1278 Region::mid_thaw (const PropertyChange& what_changed)
1280 if (what_changed.contains (Properties::length)) {
1281 if (what_changed.contains (Properties::position)) {
1282 recompute_at_start ();
1284 recompute_at_end ();
1289 Region::send_change (const PropertyChange& what_changed)
1291 if (what_changed.empty()) {
1295 Stateful::send_change (what_changed);
1297 if (!Stateful::property_changes_suspended()) {
1299 /* Try and send a shared_pointer unless this is part of the constructor.
1304 boost::shared_ptr<Region> rptr = shared_from_this();
1305 RegionPropertyChanged (rptr, what_changed);
1307 /* no shared_ptr available, relax; */
1313 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1315 return coverage (other->first_frame(), other->last_frame()) != Evoral::OverlapNone;
1319 Region::equivalent (boost::shared_ptr<const Region> other) const
1321 return _start == other->_start &&
1322 _position == other->_position &&
1323 _length == other->_length;
1327 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1329 return _start == other->_start &&
1330 _length == other->_length;
1334 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1336 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1340 Region::source_deleted (boost::weak_ptr<Source>)
1344 if (!_session.deletion_in_progress()) {
1345 /* this is a very special case: at least one of the region's
1346 sources has bee deleted, so invalidate all references to
1347 ourselves. Do NOT do this during session deletion, because
1348 then we run the risk that this will actually result
1349 in this object being deleted (as refcnt goes to zero)
1350 while emitting DropReferences.
1358 Region::master_source_names ()
1360 SourceList::iterator i;
1362 vector<string> names;
1363 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1364 names.push_back((*i)->name());
1371 Region::set_master_sources (const SourceList& srcs)
1373 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1374 (*i)->dec_use_count ();
1377 _master_sources = srcs;
1378 assert (_sources.size() == _master_sources.size());
1380 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1381 (*i)->inc_use_count ();
1386 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1391 if ((_sources.size() != other->_sources.size()) ||
1392 (_master_sources.size() != other->_master_sources.size())) {
1396 SourceList::const_iterator i;
1397 SourceList::const_iterator io;
1399 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1400 if ((*i)->id() != (*io)->id()) {
1405 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1406 if ((*i)->id() != (*io)->id()) {
1415 Region::source_string () const
1417 //string res = itos(_sources.size());
1420 res << _sources.size() << ":";
1422 SourceList::const_iterator i;
1424 for (i = _sources.begin(); i != _sources.end(); ++i) {
1425 res << (*i)->id() << ":";
1428 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1429 res << (*i)->id() << ":";
1436 Region::uses_source (boost::shared_ptr<const Source> source) const
1438 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1443 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1446 if (ps->playlist()->uses_source (source)) {
1456 Region::source_length(uint32_t n) const
1458 assert (n < _sources.size());
1459 return _sources[n]->length (_position - _start);
1463 Region::verify_length (framecnt_t len)
1465 if (source() && (source()->destructive() || source()->length_mutable())) {
1469 framecnt_t maxlen = 0;
1471 for (uint32_t n = 0; n < _sources.size(); ++n) {
1472 maxlen = max (maxlen, source_length(n) - _start);
1475 len = min (len, maxlen);
1481 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1483 if (source() && (source()->destructive() || source()->length_mutable())) {
1487 framecnt_t maxlen = 0;
1489 for (uint32_t n = 0; n < _sources.size(); ++n) {
1490 maxlen = max (maxlen, source_length(n) - new_start);
1493 new_length = min (new_length, maxlen);
1499 Region::verify_start (framepos_t pos)
1501 if (source() && (source()->destructive() || source()->length_mutable())) {
1505 for (uint32_t n = 0; n < _sources.size(); ++n) {
1506 if (pos > source_length(n) - _length) {
1514 Region::verify_start_mutable (framepos_t& new_start)
1516 if (source() && (source()->destructive() || source()->length_mutable())) {
1520 for (uint32_t n = 0; n < _sources.size(); ++n) {
1521 if (new_start > source_length(n) - _length) {
1522 new_start = source_length(n) - _length;
1528 boost::shared_ptr<Region>
1529 Region::get_parent() const
1531 boost::shared_ptr<Playlist> pl (playlist());
1534 boost::shared_ptr<Region> r;
1535 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1537 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1538 return boost::static_pointer_cast<Region> (r);
1542 return boost::shared_ptr<Region>();
1546 Region::apply (Filter& filter, Progress* progress)
1548 return filter.run (shared_from_this(), progress);
1553 Region::invalidate_transients ()
1555 _valid_transients = false;
1556 _transients.clear ();
1558 send_change (PropertyChange (Properties::valid_transients));
1562 Region::drop_sources ()
1564 for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1565 (*i)->dec_use_count ();
1570 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1571 (*i)->dec_use_count ();
1574 _master_sources.clear ();
1578 Region::use_sources (SourceList const & s)
1580 set<boost::shared_ptr<Source> > unique_srcs;
1582 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1584 _sources.push_back (*i);
1585 (*i)->inc_use_count ();
1586 _master_sources.push_back (*i);
1587 (*i)->inc_use_count ();
1589 /* connect only once to DropReferences, even if sources are replicated
1592 if (unique_srcs.find (*i) == unique_srcs.end ()) {
1593 unique_srcs.insert (*i);
1594 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1600 Region::can_trim () const
1602 CanTrim ct = CanTrim (0);
1608 /* if not locked, we can always move the front later, and the end earlier
1611 ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
1613 if (start() != 0 || can_trim_start_before_source_start ()) {
1614 ct = CanTrim (ct | FrontTrimEarlier);
1617 if (!_sources.empty()) {
1618 if ((start() + length()) < _sources.front()->length (0)) {
1619 ct = CanTrim (ct | EndTrimLater);
1627 Region::max_source_level () const
1631 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1632 lvl = max (lvl, (*i)->level());
1639 Region::is_compound () const
1641 return max_source_level() > 0;
1645 Region::post_set (const PropertyChange& pc)
1647 if (pc.contains (Properties::position)) {
1648 recompute_position_from_lock_style ();
1653 Region::set_start_internal (framecnt_t s)