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/threads.h>
27 #include "pbd/xml++.h"
29 #include "ardour/debug.h"
30 #include "ardour/filter.h"
31 #include "ardour/playlist.h"
32 #include "ardour/playlist_source.h"
33 #include "ardour/profile.h"
34 #include "ardour/region.h"
35 #include "ardour/region_factory.h"
36 #include "ardour/session.h"
37 #include "ardour/source.h"
38 #include "ardour/tempo.h"
39 #include "ardour/transient_detector.h"
44 using namespace ARDOUR;
49 namespace Properties {
50 PBD::PropertyDescriptor<bool> muted;
51 PBD::PropertyDescriptor<bool> opaque;
52 PBD::PropertyDescriptor<bool> locked;
53 PBD::PropertyDescriptor<bool> video_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<bool> valid_transients;
64 PBD::PropertyDescriptor<framepos_t> start;
65 PBD::PropertyDescriptor<framecnt_t> length;
66 PBD::PropertyDescriptor<framepos_t> position;
67 PBD::PropertyDescriptor<double> beat;
68 PBD::PropertyDescriptor<framecnt_t> sync_position;
69 PBD::PropertyDescriptor<layer_t> layer;
70 PBD::PropertyDescriptor<framepos_t> ancestral_start;
71 PBD::PropertyDescriptor<framecnt_t> ancestral_length;
72 PBD::PropertyDescriptor<float> stretch;
73 PBD::PropertyDescriptor<float> shift;
74 PBD::PropertyDescriptor<PositionLockStyle> position_lock_style;
75 PBD::PropertyDescriptor<uint64_t> layering_index;
79 PBD::Signal2<void,boost::shared_ptr<ARDOUR::Region>,const PropertyChange&> Region::RegionPropertyChanged;
82 Region::make_property_quarks ()
84 Properties::muted.property_id = g_quark_from_static_string (X_("muted"));
85 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n", Properties::muted.property_id));
86 Properties::opaque.property_id = g_quark_from_static_string (X_("opaque"));
87 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n", Properties::opaque.property_id));
88 Properties::locked.property_id = g_quark_from_static_string (X_("locked"));
89 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n", Properties::locked.property_id));
90 Properties::video_locked.property_id = g_quark_from_static_string (X_("video-locked"));
91 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for video-locked = %1\n", Properties::video_locked.property_id));
92 Properties::automatic.property_id = g_quark_from_static_string (X_("automatic"));
93 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n", Properties::automatic.property_id));
94 Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file"));
95 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n", Properties::whole_file.property_id));
96 Properties::import.property_id = g_quark_from_static_string (X_("import"));
97 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n", Properties::import.property_id));
98 Properties::external.property_id = g_quark_from_static_string (X_("external"));
99 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n", Properties::external.property_id));
100 Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked"));
101 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n", Properties::sync_marked.property_id));
102 Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split"));
103 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n", Properties::left_of_split.property_id));
104 Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split"));
105 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n", Properties::right_of_split.property_id));
106 Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
107 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id));
108 Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
109 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id));
110 Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients"));
111 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n", Properties::valid_transients.property_id));
112 Properties::start.property_id = g_quark_from_static_string (X_("start"));
113 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id));
114 Properties::length.property_id = g_quark_from_static_string (X_("length"));
115 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n", Properties::length.property_id));
116 Properties::position.property_id = g_quark_from_static_string (X_("position"));
117 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n", Properties::position.property_id));
118 Properties::beat.property_id = g_quark_from_static_string (X_("beat"));
119 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for beat = %1\n", Properties::beat.property_id));
120 Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position"));
121 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n", Properties::sync_position.property_id));
122 Properties::layer.property_id = g_quark_from_static_string (X_("layer"));
123 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n", Properties::layer.property_id));
124 Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start"));
125 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n", Properties::ancestral_start.property_id));
126 Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length"));
127 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n", Properties::ancestral_length.property_id));
128 Properties::stretch.property_id = g_quark_from_static_string (X_("stretch"));
129 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n", Properties::stretch.property_id));
130 Properties::shift.property_id = g_quark_from_static_string (X_("shift"));
131 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id));
132 Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style"));
133 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id));
134 Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index"));
135 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n", Properties::layering_index.property_id));
139 Region::register_properties ()
141 _xml_node_name = X_("Region");
143 add_property (_muted);
144 add_property (_opaque);
145 add_property (_locked);
146 add_property (_video_locked);
147 add_property (_automatic);
148 add_property (_whole_file);
149 add_property (_import);
150 add_property (_external);
151 add_property (_sync_marked);
152 add_property (_left_of_split);
153 add_property (_right_of_split);
154 add_property (_hidden);
155 add_property (_position_locked);
156 add_property (_valid_transients);
157 add_property (_start);
158 add_property (_length);
159 add_property (_position);
160 add_property (_beat);
161 add_property (_sync_position);
162 add_property (_ancestral_start);
163 add_property (_ancestral_length);
164 add_property (_stretch);
165 add_property (_shift);
166 add_property (_position_lock_style);
167 add_property (_layering_index);
170 #define REGION_DEFAULT_STATE(s,l) \
171 _sync_marked (Properties::sync_marked, false) \
172 , _left_of_split (Properties::left_of_split, false) \
173 , _right_of_split (Properties::right_of_split, false) \
174 , _valid_transients (Properties::valid_transients, false) \
175 , _start (Properties::start, (s)) \
176 , _length (Properties::length, (l)) \
177 , _position (Properties::position, 0) \
178 , _beat (Properties::beat, 0.0) \
179 , _sync_position (Properties::sync_position, (s)) \
180 , _transient_user_start (0) \
181 , _transient_analysis_start (0) \
182 , _transient_analysis_end (0) \
183 , _muted (Properties::muted, false) \
184 , _opaque (Properties::opaque, true) \
185 , _locked (Properties::locked, false) \
186 , _video_locked (Properties::video_locked, false) \
187 , _automatic (Properties::automatic, false) \
188 , _whole_file (Properties::whole_file, false) \
189 , _import (Properties::import, false) \
190 , _external (Properties::external, false) \
191 , _hidden (Properties::hidden, false) \
192 , _position_locked (Properties::position_locked, false) \
193 , _ancestral_start (Properties::ancestral_start, (s)) \
194 , _ancestral_length (Properties::ancestral_length, (l)) \
195 , _stretch (Properties::stretch, 1.0) \
196 , _shift (Properties::shift, 1.0) \
197 , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \
198 , _layering_index (Properties::layering_index, 0)
200 #define REGION_COPY_STATE(other) \
201 _sync_marked (Properties::sync_marked, other->_sync_marked) \
202 , _left_of_split (Properties::left_of_split, other->_left_of_split) \
203 , _right_of_split (Properties::right_of_split, other->_right_of_split) \
204 , _valid_transients (Properties::valid_transients, other->_valid_transients) \
205 , _start(Properties::start, other->_start) \
206 , _length(Properties::length, other->_length) \
207 , _position(Properties::position, other->_position) \
208 , _beat (Properties::beat, other->_beat) \
209 , _sync_position(Properties::sync_position, other->_sync_position) \
210 , _user_transients (other->_user_transients) \
211 , _transient_user_start (other->_transient_user_start) \
212 , _transients (other->_transients) \
213 , _transient_analysis_start (other->_transient_analysis_start) \
214 , _transient_analysis_end (other->_transient_analysis_end) \
215 , _muted (Properties::muted, other->_muted) \
216 , _opaque (Properties::opaque, other->_opaque) \
217 , _locked (Properties::locked, other->_locked) \
218 , _video_locked (Properties::video_locked, other->_video_locked) \
219 , _automatic (Properties::automatic, other->_automatic) \
220 , _whole_file (Properties::whole_file, other->_whole_file) \
221 , _import (Properties::import, other->_import) \
222 , _external (Properties::external, other->_external) \
223 , _hidden (Properties::hidden, other->_hidden) \
224 , _position_locked (Properties::position_locked, other->_position_locked) \
225 , _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \
226 , _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \
227 , _stretch (Properties::stretch, other->_stretch) \
228 , _shift (Properties::shift, other->_shift) \
229 , _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \
230 , _layering_index (Properties::layering_index, other->_layering_index)
232 /* derived-from-derived constructor (no sources in constructor) */
233 Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
234 : SessionObject(s, name)
236 , REGION_DEFAULT_STATE(start,length)
237 , _last_length (length)
239 , _first_edit (EditChangesNothing)
242 register_properties ();
244 /* no sources at this point */
247 /** Basic Region constructor (many sources) */
248 Region::Region (const SourceList& srcs)
249 : SessionObject(srcs.front()->session(), "toBeRenamed")
250 , _type (srcs.front()->type())
251 , REGION_DEFAULT_STATE(0,0)
254 , _first_edit (EditChangesNothing)
257 register_properties ();
259 _type = srcs.front()->type();
263 assert(_sources.size() > 0);
264 assert (_type == srcs.front()->type());
267 /** Create a new Region from an existing one */
268 Region::Region (boost::shared_ptr<const Region> other)
269 : SessionObject(other->session(), other->name())
270 , _type (other->data_type())
271 , REGION_COPY_STATE (other)
272 , _last_length (other->_last_length)
273 , _last_position(other->_last_position) \
274 , _first_edit (EditChangesNothing)
275 , _layer (other->_layer)
277 register_properties ();
279 /* override state that may have been incorrectly inherited from the other region
282 _position = other->_position;
287 use_sources (other->_sources);
288 set_master_sources (other->_master_sources);
290 _position_lock_style = other->_position_lock_style;
291 _first_edit = other->_first_edit;
293 _start = other->_start;
294 _beat = other->_beat;
296 /* sync pos is relative to start of file. our start-in-file is now zero,
297 so set our sync position to whatever the the difference between
298 _start and _sync_pos was in the other region.
300 result is that our new sync pos points to the same point in our source(s)
301 as the sync in the other region did in its source(s).
303 since we start at zero in our source(s), it is not possible to use a sync point that
304 is before the start. reset it to _start if that was true in the other region.
307 if (other->sync_marked()) {
308 if (other->_start < other->_sync_position) {
309 /* sync pos was after the start point of the other region */
310 _sync_position = other->_sync_position - other->_start;
312 /* sync pos was before the start point of the other region. not possible here. */
313 _sync_marked = false;
314 _sync_position = _start;
317 _sync_marked = false;
318 _sync_position = _start;
321 assert (_type == other->data_type());
324 /** Create a new Region from part of an existing one.
326 the start within \a other is given by \a offset
327 (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start()
329 Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset, const int32_t sub_num)
330 : SessionObject(other->session(), other->name())
331 , _type (other->data_type())
332 , REGION_COPY_STATE (other)
333 , _last_length (other->_last_length)
334 , _last_position(other->_last_position) \
335 , _first_edit (EditChangesNothing)
336 , _layer (other->_layer)
338 register_properties ();
340 /* override state that may have been incorrectly inherited from the other region
343 _position = other->_position + offset;
348 use_sources (other->_sources);
349 set_master_sources (other->_master_sources);
351 _start = other->_start + offset;
352 _beat = _session.tempo_map().exact_beat_at_frame (_position, sub_num);
354 /* if the other region had a distinct sync point
355 set, then continue to use it as best we can.
356 otherwise, reset sync point back to start.
359 if (other->sync_marked()) {
360 if (other->_sync_position < _start) {
361 _sync_marked = false;
362 _sync_position = _start;
364 _sync_position = other->_sync_position;
367 _sync_marked = false;
368 _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)
382 , _layer (other->_layer)
384 register_properties ();
387 _position_locked = false;
389 other->_first_edit = EditChangesName;
391 if (other->_extra_xml) {
392 _extra_xml = new XMLNode (*other->_extra_xml);
398 assert(_sources.size() > 0);
403 DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
408 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
410 _playlist = wpl.lock();
414 Region::set_name (const std::string& str)
417 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
418 assert(_name == str);
420 send_change (Properties::name);
427 Region::set_length (framecnt_t len, const int32_t sub_num)
429 //cerr << "Region::set_length() len = " << len << endl;
434 if (_length != len && len != 0) {
436 /* check that the current _position wouldn't make the new
440 if (max_framepos - len < _position) {
444 if (!verify_length (len)) {
449 set_length_internal (len, sub_num);
453 maybe_invalidate_transients ();
455 if (!property_changes_suspended()) {
459 send_change (Properties::length);
464 Region::set_length_internal (framecnt_t len, const int32_t sub_num)
466 _last_length = _length;
471 Region::maybe_uncopy ()
473 /* this does nothing but marked a semantic moment once upon a time */
477 Region::first_edit ()
479 boost::shared_ptr<Playlist> pl (playlist());
481 if (_first_edit != EditChangesNothing && pl) {
483 _name = RegionFactory::new_region_name (_name);
484 _first_edit = EditChangesNothing;
486 send_change (Properties::name);
488 RegionFactory::CheckNewRegion (shared_from_this());
493 Region::at_natural_position () const
495 boost::shared_ptr<Playlist> pl (playlist());
501 boost::shared_ptr<Region> whole_file_region = get_parent();
503 if (whole_file_region) {
504 if (_position == whole_file_region->position() + _start) {
513 Region::move_to_natural_position ()
515 boost::shared_ptr<Playlist> pl (playlist());
521 boost::shared_ptr<Region> whole_file_region = get_parent();
523 if (whole_file_region) {
524 set_position (whole_file_region->position() + _start);
529 Region::special_set_position (framepos_t pos)
531 /* this is used when creating a whole file region as
532 a way to store its "natural" or "captured" position.
535 _position = _position;
540 Region::set_position_lock_style (PositionLockStyle ps)
542 if (_position_lock_style != ps) {
544 boost::shared_ptr<Playlist> pl (playlist());
546 _position_lock_style = ps;
548 if (_position_lock_style == MusicTime) {
549 _beat = _session.tempo_map().beat_at_frame (_position);
552 send_change (Properties::position_lock_style);
557 Region::update_after_tempo_map_change (bool send)
559 boost::shared_ptr<Playlist> pl (playlist());
561 if (!pl || _position_lock_style != MusicTime) {
565 const framepos_t pos = _session.tempo_map().frame_at_beat (_beat);
566 /* we have _beat. update frame position non-musically */
567 set_position_internal (pos, false, 0);
569 /* do this even if the position is the same. this helps out
570 a GUI that has moved its representation already.
574 send_change (Properties::position);
579 Region::set_position (framepos_t pos, int32_t sub_num)
586 set_position_internal (pos, true, 0);
588 double beat = _session.tempo_map().exact_beat_at_frame (pos, sub_num);
590 set_position_internal (pos, false, sub_num);
593 /* do this even if the position is the same. this helps out
594 a GUI that has moved its representation already.
596 PropertyChange p_and_l;
598 p_and_l.add (Properties::position);
599 /* Currently length change due to position change is only implemented
600 for MidiRegion (Region has no length in beats).
601 Notify a length change regardless (its more efficient for MidiRegions),
602 and when Region has a _length_beats we will need it here anyway).
604 if (position_lock_style() == MusicTime) {
605 p_and_l.add (Properties::length);
608 send_change (p_and_l);
612 /** A gui may need to create a region, then place it in an initial
613 * position determined by the user.
614 * When this takes place within one gui operation, we have to reset
615 * _last_position to prevent an implied move.
618 Region::set_initial_position (framepos_t pos)
624 if (_position != pos) {
627 /* check that the new _position wouldn't make the current
628 length impossible - if so, change the length.
630 XXX is this the right thing to do?
633 if (max_framepos - _length < _position) {
634 _last_length = _length;
635 _length = max_framepos - _position;
638 recompute_position_from_lock_style (0);
639 /* ensure that this move doesn't cause a range move */
640 _last_position = _position;
644 /* do this even if the position is the same. this helps out
645 a GUI that has moved its representation already.
647 send_change (Properties::position);
651 Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute, const int32_t sub_num)
653 /* We emit a change of Properties::position even if the position hasn't changed
654 (see Region::set_position), so we must always set this up so that
655 e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
657 _last_position = _position;
659 if (_position != pos) {
662 if (allow_bbt_recompute) {
663 recompute_position_from_lock_style (sub_num);
665 /* check that the new _position wouldn't make the current
666 length impossible - if so, change the length.
668 XXX is this the right thing to do?
670 if (max_framepos - _length < _position) {
671 _last_length = _length;
672 _length = max_framepos - _position;
678 Region::recompute_position_from_lock_style (const int32_t sub_num)
680 _beat = _session.tempo_map().exact_beat_at_frame (_position, sub_num);
684 Region::nudge_position (frameoffset_t n)
686 if (locked() || video_locked()) {
694 framepos_t new_position = _position;
697 if (_position > max_framepos - n) {
698 new_position = max_framepos;
703 if (_position < -n) {
709 /* assumes non-musical nudge */
710 set_position_internal (new_position, true, 0);
712 send_change (Properties::position);
716 Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh)
718 _ancestral_length = l;
719 _ancestral_start = s;
725 Region::set_start (framepos_t pos)
727 if (locked() || position_locked() || video_locked()) {
730 /* This just sets the start, nothing else. It effectively shifts
731 the contents of the Region within the overall extent of the Source,
732 without changing the Region's position or length
737 if (!verify_start (pos)) {
741 set_start_internal (pos);
744 maybe_invalidate_transients ();
746 send_change (Properties::start);
751 Region::move_start (frameoffset_t distance, const int32_t sub_num)
753 if (locked() || position_locked() || video_locked()) {
757 framepos_t new_start;
761 if (_start > max_framepos - distance) {
762 new_start = max_framepos; // makes no sense
764 new_start = _start + distance;
767 if (!verify_start (new_start)) {
771 } else if (distance < 0) {
773 if (_start < -distance) {
776 new_start = _start + distance;
783 if (new_start == _start) {
787 set_start_internal (new_start, sub_num);
792 send_change (Properties::start);
796 Region::trim_front (framepos_t new_position, const int32_t sub_num)
798 modify_front (new_position, false, sub_num);
802 Region::cut_front (framepos_t new_position, const int32_t sub_num)
804 modify_front (new_position, true, sub_num);
808 Region::cut_end (framepos_t new_endpoint, const int32_t sub_num)
810 modify_end (new_endpoint, true, sub_num);
814 Region::modify_front (framepos_t new_position, bool reset_fade, const int32_t sub_num)
820 framepos_t end = last_frame();
821 framepos_t source_zero;
823 if (_position > _start) {
824 source_zero = _position - _start;
826 source_zero = 0; // its actually negative, but this will work for us
829 if (new_position < end) { /* can't trim it zero or negative length */
831 framecnt_t newlen = 0;
833 if (!can_trim_start_before_source_start ()) {
834 /* can't trim it back past where source position zero is located */
835 new_position = max (new_position, source_zero);
838 if (new_position > _position) {
839 newlen = _length - (new_position - _position);
841 newlen = _length + (_position - new_position);
844 trim_to_internal (new_position, newlen, sub_num);
847 _right_of_split = true;
850 if (!property_changes_suspended()) {
851 recompute_at_start ();
854 maybe_invalidate_transients ();
859 Region::modify_end (framepos_t new_endpoint, bool reset_fade, const int32_t sub_num)
865 if (new_endpoint > _position) {
866 trim_to_internal (_position, new_endpoint - _position, sub_num);
868 _left_of_split = true;
870 if (!property_changes_suspended()) {
876 /** @param new_endpoint New region end point, such that, for example,
877 * a region at 0 of length 10 has an endpoint of 9.
881 Region::trim_end (framepos_t new_endpoint, const int32_t sub_num)
883 modify_end (new_endpoint, false, sub_num);
887 Region::trim_to (framepos_t position, framecnt_t length, const int32_t sub_num)
893 trim_to_internal (position, length, sub_num);
895 if (!property_changes_suspended()) {
896 recompute_at_start ();
902 Region::trim_to_internal (framepos_t position, framecnt_t length, const int32_t sub_num)
904 framepos_t new_start;
910 frameoffset_t const start_shift = position - _position;
912 if (start_shift > 0) {
914 if (_start > max_framepos - start_shift) {
915 new_start = max_framepos;
917 new_start = _start + start_shift;
920 } else if (start_shift < 0) {
922 if (_start < -start_shift && !can_trim_start_before_source_start ()) {
925 new_start = _start + start_shift;
932 if (!verify_start_and_length (new_start, length)) {
936 PropertyChange what_changed;
938 if (_start != new_start) {
939 set_start_internal (new_start, sub_num);
940 what_changed.add (Properties::start);
944 /* Set position before length, otherwise for MIDI regions this bad thing happens:
945 * 1. we call set_length_internal; length in beats is computed using the region's current
946 * (soon-to-be old) position
947 * 2. we call set_position_internal; position is set and length in frames re-computed using
948 * length in beats from (1) but at the new position, which is wrong if the region
949 * straddles a tempo/meter change.
952 if (_position != position) {
953 if (!property_changes_suspended()) {
954 _last_position = _position;
956 set_position_internal (position, true, sub_num);
957 what_changed.add (Properties::position);
960 if (_length != length) {
961 if (!property_changes_suspended()) {
962 _last_length = _length;
964 set_length_internal (length, sub_num);
965 what_changed.add (Properties::length);
970 PropertyChange start_and_length;
972 start_and_length.add (Properties::start);
973 start_and_length.add (Properties::length);
975 if (what_changed.contains (start_and_length)) {
979 if (!what_changed.empty()) {
980 send_change (what_changed);
985 Region::set_hidden (bool yn)
987 if (hidden() != yn) {
989 send_change (Properties::hidden);
994 Region::set_whole_file (bool yn)
997 /* no change signal */
1001 Region::set_automatic (bool yn)
1004 /* no change signal */
1008 Region::set_muted (bool yn)
1010 if (muted() != yn) {
1012 send_change (Properties::muted);
1017 Region::set_opaque (bool yn)
1019 if (opaque() != yn) {
1021 send_change (Properties::opaque);
1026 Region::set_locked (bool yn)
1028 if (locked() != yn) {
1030 send_change (Properties::locked);
1035 Region::set_video_locked (bool yn)
1037 if (video_locked() != yn) {
1039 send_change (Properties::video_locked);
1044 Region::set_position_locked (bool yn)
1046 if (position_locked() != yn) {
1047 _position_locked = yn;
1048 send_change (Properties::locked);
1052 /** Set the region's sync point.
1053 * @param absolute_pos Session time.
1056 Region::set_sync_position (framepos_t absolute_pos)
1058 /* position within our file */
1059 framepos_t const file_pos = _start + (absolute_pos - _position);
1061 if (file_pos != _sync_position) {
1062 _sync_marked = true;
1063 _sync_position = file_pos;
1064 if (!property_changes_suspended()) {
1068 send_change (Properties::sync_position);
1073 Region::clear_sync_position ()
1075 if (sync_marked()) {
1076 _sync_marked = false;
1077 if (!property_changes_suspended()) {
1081 send_change (Properties::sync_position);
1085 /* @return the sync point relative the first frame of the region */
1087 Region::sync_offset (int& dir) const
1089 if (sync_marked()) {
1090 if (_sync_position > _start) {
1092 return _sync_position - _start;
1095 return _start - _sync_position;
1104 Region::adjust_to_sync (framepos_t pos) const
1107 frameoffset_t offset = sync_offset (sync_dir);
1109 // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1118 if (max_framepos - pos > offset) {
1126 /** @return Sync position in session time */
1128 Region::sync_position() const
1130 if (sync_marked()) {
1131 return _position - _start + _sync_position;
1133 /* if sync has not been marked, use the start of the region */
1141 boost::shared_ptr<Playlist> pl (playlist());
1143 pl->raise_region (shared_from_this ());
1150 boost::shared_ptr<Playlist> pl (playlist());
1152 pl->lower_region (shared_from_this ());
1158 Region::raise_to_top ()
1160 boost::shared_ptr<Playlist> pl (playlist());
1162 pl->raise_region_to_top (shared_from_this());
1167 Region::lower_to_bottom ()
1169 boost::shared_ptr<Playlist> pl (playlist());
1171 pl->lower_region_to_bottom (shared_from_this());
1176 Region::set_layer (layer_t l)
1184 XMLNode *node = new XMLNode ("Region");
1188 const char* fe = NULL;
1190 /* custom version of 'add_properties (*node);'
1191 * skip values that have have dedicated save functions
1192 * in AudioRegion::state()
1194 for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
1195 if (!strcmp(i->second->property_name(), (const char*)"Envelope")) continue;
1196 if (!strcmp(i->second->property_name(), (const char*)"FadeIn")) continue;
1197 if (!strcmp(i->second->property_name(), (const char*)"FadeOut")) continue;
1198 if (!strcmp(i->second->property_name(), (const char*)"InverseFadeIn")) continue;
1199 if (!strcmp(i->second->property_name(), (const char*)"InverseFadeOut")) continue;
1200 i->second->get_value (*node);
1203 id().print (buf, sizeof (buf));
1204 node->add_property ("id", buf);
1205 node->add_property ("type", _type.to_string());
1207 switch (_first_edit) {
1208 case EditChangesNothing:
1211 case EditChangesName:
1217 default: /* should be unreachable but makes g++ happy */
1222 node->add_property ("first-edit", fe);
1224 /* note: flags are stored by derived classes */
1226 for (uint32_t n=0; n < _sources.size(); ++n) {
1227 snprintf (buf2, sizeof(buf2), "source-%d", n);
1228 _sources[n]->id().print (buf, sizeof(buf));
1229 node->add_property (buf2, buf);
1232 for (uint32_t n=0; n < _master_sources.size(); ++n) {
1233 snprintf (buf2, sizeof(buf2), "master-source-%d", n);
1234 _master_sources[n]->id().print (buf, sizeof (buf));
1235 node->add_property (buf2, buf);
1238 /* Only store nested sources for the whole-file region that acts
1239 as the parent/root of all regions using it.
1242 if (_whole_file && max_source_level() > 0) {
1244 XMLNode* nested_node = new XMLNode (X_("NestedSource"));
1246 /* region is compound - get its playlist and
1247 store that before we list the region that
1251 for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) {
1252 nested_node->add_child_nocopy ((*s)->get_state ());
1256 node->add_child_nocopy (*nested_node);
1261 node->add_child_copy (*_extra_xml);
1268 Region::get_state ()
1274 Region::set_state (const XMLNode& node, int version)
1276 PropertyChange what_changed;
1277 return _set_state (node, version, what_changed, true);
1281 Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
1283 XMLProperty const * prop;
1284 Timecode::BBT_Time bbt_time;
1286 Stateful::save_extra_xml (node);
1288 what_changed = set_values (node);
1292 if (_position_lock_style == MusicTime) {
1293 if ((prop = node.property ("bbt-position")) != 0) {
1294 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1297 &bbt_time.ticks) != 3) {
1298 _position_lock_style = AudioTime;
1300 _beat = _session.tempo_map().beat_at_bbt (bbt_time);
1305 /* fix problems with old sessions corrupted by impossible
1306 values for _stretch or _shift
1308 if (_stretch == 0.0f) {
1312 if (_shift == 0.0f) {
1317 send_change (what_changed);
1320 /* Quick fix for 2.x sessions when region is muted */
1321 if ((prop = node.property (X_("flags")))) {
1322 if (string::npos != prop->value().find("Muted")){
1327 // saved property is invalid, region-transients are not saved
1328 if (_user_transients.size() == 0){
1329 _valid_transients = false;
1336 Region::suspend_property_changes ()
1338 Stateful::suspend_property_changes ();
1339 _last_length = _length;
1340 _last_position = _position;
1344 Region::mid_thaw (const PropertyChange& what_changed)
1346 if (what_changed.contains (Properties::length)) {
1347 if (what_changed.contains (Properties::position)) {
1348 recompute_at_start ();
1350 recompute_at_end ();
1355 Region::send_change (const PropertyChange& what_changed)
1357 if (what_changed.empty()) {
1361 Stateful::send_change (what_changed);
1363 if (!Stateful::property_changes_suspended()) {
1365 /* Try and send a shared_pointer unless this is part of the constructor.
1370 boost::shared_ptr<Region> rptr = shared_from_this();
1371 RegionPropertyChanged (rptr, what_changed);
1373 /* no shared_ptr available, relax; */
1379 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1381 return coverage (other->first_frame(), other->last_frame()) != Evoral::OverlapNone;
1385 Region::equivalent (boost::shared_ptr<const Region> other) const
1387 return _start == other->_start &&
1388 _position == other->_position &&
1389 _length == other->_length;
1393 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1395 return _start == other->_start &&
1396 _length == other->_length;
1400 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1402 return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1406 Region::source_deleted (boost::weak_ptr<Source>)
1410 if (!_session.deletion_in_progress()) {
1411 /* this is a very special case: at least one of the region's
1412 sources has bee deleted, so invalidate all references to
1413 ourselves. Do NOT do this during session deletion, because
1414 then we run the risk that this will actually result
1415 in this object being deleted (as refcnt goes to zero)
1416 while emitting DropReferences.
1424 Region::master_source_names ()
1426 SourceList::iterator i;
1428 vector<string> names;
1429 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1430 names.push_back((*i)->name());
1437 Region::set_master_sources (const SourceList& srcs)
1439 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1440 (*i)->dec_use_count ();
1443 _master_sources = srcs;
1444 assert (_sources.size() == _master_sources.size());
1446 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1447 (*i)->inc_use_count ();
1452 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1457 if ((_sources.size() != other->_sources.size()) ||
1458 (_master_sources.size() != other->_master_sources.size())) {
1462 SourceList::const_iterator i;
1463 SourceList::const_iterator io;
1465 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1466 if ((*i)->id() != (*io)->id()) {
1471 for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1472 if ((*i)->id() != (*io)->id()) {
1481 Region::any_source_equivalent (boost::shared_ptr<const Region> other) const
1487 SourceList::const_iterator i;
1488 SourceList::const_iterator io;
1490 for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1491 if ((*i)->id() == (*io)->id()) {
1500 Region::source_string () const
1502 //string res = itos(_sources.size());
1505 res << _sources.size() << ":";
1507 SourceList::const_iterator i;
1509 for (i = _sources.begin(); i != _sources.end(); ++i) {
1510 res << (*i)->id() << ":";
1513 for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1514 res << (*i)->id() << ":";
1521 Region::deep_sources (std::set<boost::shared_ptr<Source> > & sources) const
1523 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1525 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1528 if (sources.find (ps) == sources.end()) {
1529 /* (Playlist)Source not currently in
1530 accumulating set, so recurse.
1532 ps->playlist()->deep_sources (sources);
1536 /* add this source */
1537 sources.insert (*i);
1540 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1542 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1545 if (sources.find (ps) == sources.end()) {
1546 /* (Playlist)Source not currently in
1547 accumulating set, so recurse.
1549 ps->playlist()->deep_sources (sources);
1553 /* add this source */
1554 sources.insert (*i);
1559 Region::uses_source (boost::shared_ptr<const Source> source, bool shallow) const
1561 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1567 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1570 if (ps->playlist()->uses_source (source)) {
1577 for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1583 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1586 if (ps->playlist()->uses_source (source)) {
1598 Region::source_length(uint32_t n) const
1600 assert (n < _sources.size());
1601 return _sources[n]->length (_position - _start);
1605 Region::verify_length (framecnt_t& len)
1607 if (source() && (source()->destructive() || source()->length_mutable())) {
1611 framecnt_t maxlen = 0;
1613 for (uint32_t n = 0; n < _sources.size(); ++n) {
1614 maxlen = max (maxlen, source_length(n) - _start);
1617 len = min (len, maxlen);
1623 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1625 if (source() && (source()->destructive() || source()->length_mutable())) {
1629 framecnt_t maxlen = 0;
1631 for (uint32_t n = 0; n < _sources.size(); ++n) {
1632 maxlen = max (maxlen, source_length(n) - new_start);
1635 new_length = min (new_length, maxlen);
1641 Region::verify_start (framepos_t pos)
1643 if (source() && (source()->destructive() || source()->length_mutable())) {
1647 for (uint32_t n = 0; n < _sources.size(); ++n) {
1648 if (pos > source_length(n) - _length) {
1656 Region::verify_start_mutable (framepos_t& new_start)
1658 if (source() && (source()->destructive() || source()->length_mutable())) {
1662 for (uint32_t n = 0; n < _sources.size(); ++n) {
1663 if (new_start > source_length(n) - _length) {
1664 new_start = source_length(n) - _length;
1670 boost::shared_ptr<Region>
1671 Region::get_parent() const
1673 boost::shared_ptr<Playlist> pl (playlist());
1676 boost::shared_ptr<Region> r;
1677 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1679 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1680 return boost::static_pointer_cast<Region> (r);
1684 return boost::shared_ptr<Region>();
1688 Region::apply (Filter& filter, Progress* progress)
1690 return filter.run (shared_from_this(), progress);
1695 Region::maybe_invalidate_transients ()
1697 bool changed = !_onsets.empty();
1700 if (_valid_transients || changed) {
1701 send_change (PropertyChange (Properties::valid_transients));
1707 Region::transients (AnalysisFeatureList& afl)
1709 int cnt = afl.empty() ? 0 : 1;
1711 Region::merge_features (afl, _onsets, _position);
1712 Region::merge_features (afl, _user_transients, _position + _transient_user_start - _start);
1713 if (!_onsets.empty ()) {
1716 if (!_user_transients.empty ()) {
1721 // remove exact duplicates
1722 TransientDetector::cleanup_transients (afl, _session.frame_rate(), 0);
1727 Region::has_transients () const
1729 if (!_user_transients.empty ()) {
1730 assert (_valid_transients);
1733 if (!_onsets.empty ()) {
1740 Region::merge_features (AnalysisFeatureList& result, const AnalysisFeatureList& src, const frameoffset_t off) const
1742 for (AnalysisFeatureList::const_iterator x = src.begin(); x != src.end(); ++x) {
1743 const frameoffset_t p = (*x) + off;
1744 if (p < first_frame() || p > last_frame()) {
1747 result.push_back (p);
1752 Region::drop_sources ()
1754 for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1755 (*i)->dec_use_count ();
1760 for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1761 (*i)->dec_use_count ();
1764 _master_sources.clear ();
1768 Region::use_sources (SourceList const & s)
1770 set<boost::shared_ptr<Source> > unique_srcs;
1772 for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1774 _sources.push_back (*i);
1775 (*i)->inc_use_count ();
1776 _master_sources.push_back (*i);
1777 (*i)->inc_use_count ();
1779 /* connect only once to DropReferences, even if sources are replicated
1782 if (unique_srcs.find (*i) == unique_srcs.end ()) {
1783 unique_srcs.insert (*i);
1784 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1790 Region::can_trim () const
1792 CanTrim ct = CanTrim (0);
1798 /* if not locked, we can always move the front later, and the end earlier
1801 ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
1803 if (start() != 0 || can_trim_start_before_source_start ()) {
1804 ct = CanTrim (ct | FrontTrimEarlier);
1807 if (!_sources.empty()) {
1808 if ((start() + length()) < _sources.front()->length (0)) {
1809 ct = CanTrim (ct | EndTrimLater);
1817 Region::max_source_level () const
1821 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1822 lvl = max (lvl, (*i)->level());
1829 Region::is_compound () const
1831 return max_source_level() > 0;
1835 Region::post_set (const PropertyChange& pc)
1837 if (pc.contains (Properties::position)) {
1838 recompute_position_from_lock_style (0);
1843 Region::set_start_internal (framecnt_t s, const int32_t sub_num)
1849 Region::earliest_possible_position () const
1851 if (_start > _position) {
1854 return _position - _start;
1859 Region::latest_possible_frame () const
1861 framecnt_t minlen = max_framecnt;
1863 for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1864 /* non-audio regions have a length that may vary based on their
1865 * position, so we have to pass it in the call.
1867 minlen = min (minlen, (*i)->length (_position));
1870 /* the latest possible last frame is determined by the current
1871 * position, plus the shortest source extent past _start.
1874 return _position + (minlen - _start) - 1;