stupid hack to fix issues with OS X Carbon headers
[ardour.git] / libs / ardour / region.cc
1 /*
2     Copyright (C) 2000-2003 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <iostream>
21 #include <cmath>
22 #include <climits>
23 #include <algorithm>
24 #include <sstream>
25
26 #include <glibmm/thread.h>
27 #include "pbd/xml++.h"
28 #include "pbd/stacktrace.h"
29 #include "pbd/enumwriter.h"
30
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"
44
45 #include "i18n.h"
46
47 using namespace std;
48 using namespace ARDOUR;
49 using namespace PBD;
50
51 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<framepos_t> last_relayer_bounds_from;
77                 PBD::PropertyDescriptor<framepos_t> last_relayer_bounds_to;
78                 PBD::PropertyDescriptor<uint64_t> last_layer_op_add;
79                 PBD::PropertyDescriptor<uint64_t> last_layer_op_bounds_change;
80         }
81 }
82
83 PBD::Signal2<void,boost::shared_ptr<ARDOUR::Region>,const PropertyChange&> Region::RegionPropertyChanged;
84
85 void
86 Region::make_property_quarks ()
87 {
88         Properties::muted.property_id = g_quark_from_static_string (X_("muted"));
89         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n",       Properties::muted.property_id));
90         Properties::opaque.property_id = g_quark_from_static_string (X_("opaque"));
91         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n",      Properties::opaque.property_id));
92         Properties::locked.property_id = g_quark_from_static_string (X_("locked"));
93         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n",      Properties::locked.property_id));
94         Properties::automatic.property_id = g_quark_from_static_string (X_("automatic"));
95         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n",   Properties::automatic.property_id));
96         Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file"));
97         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n",  Properties::whole_file.property_id));
98         Properties::import.property_id = g_quark_from_static_string (X_("import"));
99         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n",      Properties::import.property_id));
100         Properties::external.property_id = g_quark_from_static_string (X_("external"));
101         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n",    Properties::external.property_id));
102         Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked"));
103         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n",         Properties::sync_marked.property_id));
104         Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split"));
105         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n",       Properties::left_of_split.property_id));
106         Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split"));
107         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n",      Properties::right_of_split.property_id));
108         Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
109         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n",      Properties::hidden.property_id));
110         Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
111         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n",     Properties::position_locked.property_id));
112         Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients"));
113         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n",    Properties::valid_transients.property_id));
114         Properties::start.property_id = g_quark_from_static_string (X_("start"));
115         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n",       Properties::start.property_id));
116         Properties::length.property_id = g_quark_from_static_string (X_("length"));
117         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n",      Properties::length.property_id));
118         Properties::position.property_id = g_quark_from_static_string (X_("position"));
119         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n",    Properties::position.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::last_relayer_bounds_from.property_id = g_quark_from_static_string (X_("last-relayer-bounds-from"));
135         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_relayer_bounds_from = %1\n",    Properties::last_relayer_bounds_from.property_id));
136         Properties::last_relayer_bounds_to.property_id = g_quark_from_static_string (X_("last-relayer-bounds-to"));
137         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_relayer_bounds_to = %1\n",      Properties::last_relayer_bounds_to.property_id));
138         Properties::last_layer_op_add.property_id = g_quark_from_static_string (X_("last-layer-op-add"));
139         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_layer_op_add = %1\n", Properties::last_layer_op_add.property_id));
140         Properties::last_layer_op_bounds_change.property_id = g_quark_from_static_string (X_("last-layer-op-bounds-change"));
141         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_layer_op_bounds_change = %1\n", Properties::last_layer_op_bounds_change.property_id));
142 }
143
144 void
145 Region::register_properties ()
146 {
147         _xml_node_name = X_("Region");
148
149         add_property (_muted);
150         add_property (_opaque);
151         add_property (_locked);
152         add_property (_automatic);
153         add_property (_whole_file);
154         add_property (_import);
155         add_property (_external);
156         add_property (_sync_marked);
157         add_property (_left_of_split);
158         add_property (_right_of_split);
159         add_property (_hidden);
160         add_property (_position_locked);
161         add_property (_valid_transients);
162         add_property (_start);
163         add_property (_length);
164         add_property (_position);
165         add_property (_sync_position);
166         add_property (_layer);
167         add_property (_ancestral_start);
168         add_property (_ancestral_length);
169         add_property (_stretch);
170         add_property (_shift);
171         add_property (_position_lock_style);
172         add_property (_last_relayer_bounds_from);
173         add_property (_last_relayer_bounds_to);
174         add_property (_last_layer_op_add);
175         add_property (_last_layer_op_bounds_change);
176 }
177
178 #define REGION_DEFAULT_STATE(s,l) \
179         _sync_marked (Properties::sync_marked, false) \
180         , _left_of_split (Properties::left_of_split, false) \
181         , _right_of_split (Properties::right_of_split, false) \
182         , _valid_transients (Properties::valid_transients, false) \
183         , _start (Properties::start, (s))       \
184         , _length (Properties::length, (l))     \
185         , _position (Properties::position, 0) \
186         , _sync_position (Properties::sync_position, (s)) \
187         , _layer (Properties::layer, 0) \
188         , _muted (Properties::muted, false) \
189         , _opaque (Properties::opaque, true) \
190         , _locked (Properties::locked, false) \
191         , _automatic (Properties::automatic, false) \
192         , _whole_file (Properties::whole_file, false) \
193         , _import (Properties::import, false) \
194         , _external (Properties::external, false) \
195         , _hidden (Properties::hidden, false) \
196         , _position_locked (Properties::position_locked, false) \
197         , _ancestral_start (Properties::ancestral_start, (s)) \
198         , _ancestral_length (Properties::ancestral_length, (l)) \
199         , _stretch (Properties::stretch, 1.0) \
200         , _shift (Properties::shift, 1.0) \
201         , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \
202         , _last_relayer_bounds_from (Properties::last_relayer_bounds_from, 0) \
203         , _last_relayer_bounds_to (Properties::last_relayer_bounds_to, 0)       \
204         , _last_layer_op_add (Properties::last_layer_op_add, 0) \
205         , _last_layer_op_bounds_change (Properties::last_layer_op_bounds_change, 0)
206
207 #define REGION_COPY_STATE(other) \
208           _sync_marked (Properties::sync_marked, other->_sync_marked) \
209         , _left_of_split (Properties::left_of_split, other->_left_of_split) \
210         , _right_of_split (Properties::right_of_split, other->_right_of_split) \
211         , _valid_transients (Properties::valid_transients, other->_valid_transients) \
212         , _start(Properties::start, other->_start)              \
213         , _length(Properties::length, other->_length)           \
214         , _position(Properties::position, other->_position)     \
215         , _sync_position(Properties::sync_position, other->_sync_position) \
216         , _layer (Properties::layer, other->_layer)             \
217         , _muted (Properties::muted, other->_muted)             \
218         , _opaque (Properties::opaque, other->_opaque)          \
219         , _locked (Properties::locked, other->_locked)          \
220         , _automatic (Properties::automatic, other->_automatic) \
221         , _whole_file (Properties::whole_file, other->_whole_file) \
222         , _import (Properties::import, other->_import)          \
223         , _external (Properties::external, other->_external)    \
224         , _hidden (Properties::hidden, other->_hidden)          \
225         , _position_locked (Properties::position_locked, other->_position_locked) \
226         , _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \
227         , _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \
228         , _stretch (Properties::stretch, other->_stretch)       \
229         , _shift (Properties::shift, other->_shift)             \
230         , _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \
231         , _last_relayer_bounds_from (Properties::last_relayer_bounds_from, other->_last_relayer_bounds_from) \
232         , _last_relayer_bounds_to (Properties::last_relayer_bounds_to, other->_last_relayer_bounds_to) \
233         , _last_layer_op_add (Properties::last_layer_op_add, other->_last_layer_op_add) \
234         , _last_layer_op_bounds_change (Properties::last_layer_op_bounds_change, other->_last_layer_op_bounds_change)
235
236 /* derived-from-derived constructor (no sources in constructor) */
237 Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
238         : SessionObject(s, name)
239         , _type(type)
240         , REGION_DEFAULT_STATE(start,length)
241         , _last_length (length)
242         , _last_position (0)
243         , _first_edit (EditChangesNothing)
244 {
245         register_properties ();
246         /* no sources at this point */
247 }
248
249 /** Basic Region constructor (many sources) */
250 Region::Region (const SourceList& srcs)
251         : SessionObject(srcs.front()->session(), "toBeRenamed")
252         , _type (srcs.front()->type())
253         , REGION_DEFAULT_STATE(0,0)
254         , _last_length (0)
255         , _last_position (0)
256         , _first_edit (EditChangesNothing)
257 {
258         register_properties ();
259
260         _type = srcs.front()->type();
261
262         use_sources (srcs);
263
264         assert(_sources.size() > 0);
265         assert (_type == srcs.front()->type());
266 }
267
268 /** Create a new Region from an existing one */
269 Region::Region (boost::shared_ptr<const Region> other)
270         : SessionObject(other->session(), other->name())
271         , _type (other->data_type())
272         , REGION_COPY_STATE (other)
273         , _last_length (other->_last_length)
274         , _last_position(other->_last_position) \
275         , _first_edit (EditChangesNothing)
276 {
277         register_properties ();
278
279         /* override state that may have been incorrectly inherited from the other region
280          */
281
282         _position = 0;
283         _locked = false;
284         _whole_file = false;
285         _hidden = false;
286
287         use_sources (other->_sources);
288
289         _position_lock_style = other->_position_lock_style;
290         _first_edit = other->_first_edit;
291
292         _start = 0; // It seems strange _start is not inherited here?
293
294         /* sync pos is relative to start of file. our start-in-file is now zero,
295            so set our sync position to whatever the the difference between
296            _start and _sync_pos was in the other region.
297
298            result is that our new sync pos points to the same point in our source(s)
299            as the sync in the other region did in its source(s).
300
301            since we start at zero in our source(s), it is not possible to use a sync point that
302            is before the start. reset it to _start if that was true in the other region.
303         */
304
305         if (other->sync_marked()) {
306                 if (other->_start < other->_sync_position) {
307                         /* sync pos was after the start point of the other region */
308                         _sync_position = other->_sync_position - other->_start;
309                 } else {
310                         /* sync pos was before the start point of the other region. not possible here. */
311                         _sync_marked = false;
312                         _sync_position = _start;
313                 }
314         } else {
315                 _sync_marked = false;
316                 _sync_position = _start;
317         }
318
319         if (Profile->get_sae()) {
320                 /* reset sync point to start if its ended up
321                    outside region bounds.
322                 */
323
324                 if (_sync_position < _start || _sync_position >= _start + _length) {
325                         _sync_marked = false;
326                         _sync_position = _start;
327                 }
328         }
329
330         assert (_type == other->data_type());
331 }
332
333 /** Create a new Region from part of an existing one.
334
335     the start within \a other is given by \a offset
336     (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start()
337 */
338 Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset)
339         : SessionObject(other->session(), other->name())
340         , _type (other->data_type())
341         , REGION_COPY_STATE (other)
342         , _last_length (other->_last_length)
343         , _last_position(other->_last_position) \
344         , _first_edit (EditChangesNothing)
345 {
346         register_properties ();
347
348         /* override state that may have been incorrectly inherited from the other region
349          */
350
351         _position = 0;
352         _locked = false;
353         _whole_file = false;
354         _hidden = false;
355
356         use_sources (other->_sources);
357
358         _start = other->_start + offset;
359
360         /* if the other region had a distinct sync point
361            set, then continue to use it as best we can.
362            otherwise, reset sync point back to start.
363         */
364
365         if (other->sync_marked()) {
366                 if (other->_sync_position < _start) {
367                         _sync_marked = false;
368                         _sync_position = _start;
369                 } else {
370                         _sync_position = other->_sync_position;
371                 }
372         } else {
373                 _sync_marked = false;
374                 _sync_position = _start;
375         }
376
377         if (Profile->get_sae()) {
378                 /* reset sync point to start if its ended up
379                    outside region bounds.
380                 */
381
382                 if (_sync_position < _start || _sync_position >= _start + _length) {
383                         _sync_marked = false;
384                         _sync_position = _start;
385                 }
386         }
387
388         assert (_type == other->data_type());
389 }
390
391 /** Create a copy of @param other but with different sources. Used by filters */
392 Region::Region (boost::shared_ptr<const Region> other, const SourceList& srcs)
393         : SessionObject (other->session(), other->name())
394         , _type (srcs.front()->type())
395         , REGION_COPY_STATE (other)
396         , _last_length (other->_last_length)
397         , _last_position (other->_last_position)
398         , _first_edit (EditChangesID)
399 {
400         register_properties ();
401
402         _locked = false;
403         _position_locked = false;
404
405         other->_first_edit = EditChangesName;
406
407         if (other->_extra_xml) {
408                 _extra_xml = new XMLNode (*other->_extra_xml);
409         } else {
410                 _extra_xml = 0;
411         }
412
413         use_sources (srcs);
414         assert(_sources.size() > 0);
415 }
416
417 Region::~Region ()
418 {
419         DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
420         drop_sources ();
421 }
422
423 void
424 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
425 {
426         _playlist = wpl.lock();
427 }
428
429 bool
430 Region::set_name (const std::string& str)
431 {
432         if (_name != str) {
433                 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
434                 assert(_name == str);
435
436                 send_change (Properties::name);
437         }
438
439         return true;
440 }
441
442 void
443 Region::set_length (framecnt_t len)
444 {
445         //cerr << "Region::set_length() len = " << len << endl;
446         if (locked()) {
447                 return;
448         }
449
450         if (_length != len && len != 0) {
451
452                 /* check that the current _position wouldn't make the new
453                    length impossible.
454                 */
455
456                 if (max_framepos - len < _position) {
457                         return;
458                 }
459
460                 if (!verify_length (len)) {
461                         return;
462                 }
463
464
465                 _last_length = _length;
466                 set_length_internal (len);
467                 _whole_file = false;
468                 first_edit ();
469                 maybe_uncopy ();
470                 invalidate_transients ();
471
472                 if (!property_changes_suspended()) {
473                         recompute_at_end ();
474                 }
475
476                 send_change (Properties::length);
477         }
478 }
479
480 void
481 Region::set_length_internal (framecnt_t len)
482 {
483         _length = len;
484 }
485
486 void
487 Region::maybe_uncopy ()
488 {
489         /* this does nothing but marked a semantic moment once upon a time */
490 }
491
492 void
493 Region::first_edit ()
494 {
495         boost::shared_ptr<Playlist> pl (playlist());
496
497         if (_first_edit != EditChangesNothing && pl) {
498
499                 _name = RegionFactory::new_region_name (_name);
500                 _first_edit = EditChangesNothing;
501
502                 send_change (Properties::name);
503
504                 RegionFactory::CheckNewRegion (shared_from_this());
505         }
506 }
507
508 bool
509 Region::at_natural_position () const
510 {
511         boost::shared_ptr<Playlist> pl (playlist());
512
513         if (!pl) {
514                 return false;
515         }
516
517         boost::shared_ptr<Region> whole_file_region = get_parent();
518
519         if (whole_file_region) {
520                 if (_position == whole_file_region->position() + _start) {
521                         return true;
522                 }
523         }
524
525         return false;
526 }
527
528 void
529 Region::move_to_natural_position ()
530 {
531         boost::shared_ptr<Playlist> pl (playlist());
532
533         if (!pl) {
534                 return;
535         }
536
537         boost::shared_ptr<Region> whole_file_region = get_parent();
538
539         if (whole_file_region) {
540                 set_position (whole_file_region->position() + _start);
541         }
542 }
543
544 void
545 Region::special_set_position (framepos_t pos)
546 {
547         /* this is used when creating a whole file region as
548            a way to store its "natural" or "captured" position.
549         */
550
551         _position = _position;
552         _position = pos;
553 }
554
555 void
556 Region::set_position_lock_style (PositionLockStyle ps)
557 {
558         if (_position_lock_style != ps) {
559
560                 boost::shared_ptr<Playlist> pl (playlist());
561
562                 _position_lock_style = ps;
563
564                 if (_position_lock_style == MusicTime) {
565                         _session.tempo_map().bbt_time (_position, _bbt_time);
566                 }
567
568                 send_change (Properties::position_lock_style);
569         }
570 }
571
572 void
573 Region::update_after_tempo_map_change ()
574 {
575         boost::shared_ptr<Playlist> pl (playlist());
576
577         if (!pl || _position_lock_style != MusicTime) {
578                 return;
579         }
580
581         TempoMap& map (_session.tempo_map());
582         framepos_t pos = map.frame_time (_bbt_time);
583         set_position_internal (pos, false);
584
585         /* do this even if the position is the same. this helps out
586            a GUI that has moved its representation already.
587         */
588         send_change (Properties::position);
589 }
590
591 void
592 Region::set_position (framepos_t pos)
593 {
594         if (!can_move()) {
595                 return;
596         }
597
598         set_position_internal (pos, true);
599
600         /* do this even if the position is the same. this helps out
601            a GUI that has moved its representation already.
602         */
603         send_change (Properties::position);
604
605 }
606
607 void
608 Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
609 {
610         /* We emit a change of Properties::position even if the position hasn't changed
611            (see Region::set_position), so we must always set this up so that
612            e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
613         */
614         _last_position = _position;
615         
616         if (_position != pos) {
617                 _position = pos;
618
619                 /* check that the new _position wouldn't make the current
620                    length impossible - if so, change the length.
621
622                    XXX is this the right thing to do?
623                 */
624
625                 if (max_framepos - _length < _position) {
626                         _last_length = _length;
627                         _length = max_framepos - _position;
628                 }
629
630                 if (allow_bbt_recompute) {
631                         recompute_position_from_lock_style ();
632                 }
633
634                 //invalidate_transients ();
635         }
636 }
637
638 void
639 Region::recompute_position_from_lock_style ()
640 {
641         if (_position_lock_style == MusicTime) {
642                 _session.tempo_map().bbt_time (_position, _bbt_time);
643         }
644 }
645
646 void
647 Region::nudge_position (frameoffset_t n)
648 {
649         if (locked()) {
650                 return;
651         }
652
653         if (n == 0) {
654                 return;
655         }
656
657         framepos_t new_position = _position;
658
659         if (n > 0) {
660                 if (_position > max_framepos - n) {
661                         new_position = max_framepos;
662                 } else {
663                         new_position += n;
664                 }
665         } else {
666                 if (_position < -n) {
667                         new_position = 0;
668                 } else {
669                         new_position += n;
670                 }
671         }
672
673         set_position_internal (new_position, true);
674
675         send_change (Properties::position);
676 }
677
678 void
679 Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh)
680 {
681         _ancestral_length = l;
682         _ancestral_start = s;
683         _stretch = st;
684         _shift = sh;
685 }
686
687 void
688 Region::set_start (framepos_t pos)
689 {
690         if (locked() || position_locked()) {
691                 return;
692         }
693         /* This just sets the start, nothing else. It effectively shifts
694            the contents of the Region within the overall extent of the Source,
695            without changing the Region's position or length
696         */
697
698         if (_start != pos) {
699
700                 if (!verify_start (pos)) {
701                         return;
702                 }
703
704                 _start = pos;
705                 _whole_file = false;
706                 first_edit ();
707                 invalidate_transients ();
708
709                 send_change (Properties::start);
710         }
711 }
712
713 void
714 Region::trim_start (framepos_t new_position)
715 {
716         if (locked() || position_locked()) {
717                 return;
718         }
719         framepos_t new_start;
720         frameoffset_t const start_shift = new_position - _position;
721
722         if (start_shift > 0) {
723
724                 if (_start > max_framepos - start_shift) {
725                         new_start = max_framepos;
726                 } else {
727                         new_start = _start + start_shift;
728                 }
729
730                 if (!verify_start (new_start)) {
731                         return;
732                 }
733
734         } else if (start_shift < 0) {
735
736                 if (_start < -start_shift) {
737                         new_start = 0;
738                 } else {
739                         new_start = _start + start_shift;
740                 }
741
742         } else {
743                 return;
744         }
745
746         if (new_start == _start) {
747                 return;
748         }
749
750         _start = new_start;
751         _whole_file = false;
752         first_edit ();
753
754         send_change (Properties::start);
755 }
756
757 void
758 Region::trim_front (framepos_t new_position)
759 {
760         modify_front (new_position, false);
761 }
762
763 void
764 Region::cut_front (framepos_t new_position)
765 {
766         modify_front (new_position, true);
767 }
768
769 void
770 Region::cut_end (framepos_t new_endpoint)
771 {
772         modify_end (new_endpoint, true);
773 }
774
775 void
776 Region::modify_front (framepos_t new_position, bool reset_fade)
777 {
778         if (locked()) {
779                 return;
780         }
781
782         framepos_t end = last_frame();
783         framepos_t source_zero;
784
785         if (_position > _start) {
786                 source_zero = _position - _start;
787         } else {
788                 source_zero = 0; // its actually negative, but this will work for us
789         }
790
791         if (new_position < end) { /* can't trim it zero or negative length */
792
793                 framecnt_t newlen = 0;
794                 framepos_t delta = 0;
795
796                 if (!can_trim_start_before_source_start ()) {
797                         /* can't trim it back past where source position zero is located */
798                         new_position = max (new_position, source_zero);
799                 }
800
801                 if (new_position > _position) {
802                         newlen = _length - (new_position - _position);
803                         delta = -1 * (new_position - _position);
804                 } else {
805                         newlen = _length + (_position - new_position);
806                         delta = _position - new_position;
807                 }
808
809                 trim_to_internal (new_position, newlen);
810
811                 if (reset_fade) {
812                         _right_of_split = true;
813                 }
814
815                 if (!property_changes_suspended()) {
816                         recompute_at_start ();
817                 }
818
819                 if (_transients.size() > 0){
820                         adjust_transients(delta);
821                 }
822         }
823 }
824
825 void
826 Region::modify_end (framepos_t new_endpoint, bool reset_fade)
827 {
828         if (locked()) {
829                 return;
830         }
831
832         if (new_endpoint > _position) {
833                 trim_to_internal (_position, new_endpoint - _position);
834                 if (reset_fade) {
835                         _left_of_split = true;
836                 }
837                 if (!property_changes_suspended()) {
838                         recompute_at_end ();
839                 }
840         }
841 }
842
843 /** @param new_endpoint New region end point, such that, for example,
844  *  a region at 0 of length 10 has an endpoint of 9.
845  */
846
847 void
848 Region::trim_end (framepos_t new_endpoint)
849 {
850         modify_end (new_endpoint, false);
851 }
852
853 void
854 Region::trim_to (framepos_t position, framecnt_t length)
855 {
856         if (locked()) {
857                 return;
858         }
859
860         trim_to_internal (position, length);
861
862         if (!property_changes_suspended()) {
863                 recompute_at_start ();
864                 recompute_at_end ();
865         }
866 }
867
868 void
869 Region::trim_to_internal (framepos_t position, framecnt_t length)
870 {
871         framepos_t new_start;
872
873         if (locked()) {
874                 return;
875         }
876
877         frameoffset_t const start_shift = position - _position;
878
879         if (start_shift > 0) {
880
881                 if (_start > max_framepos - start_shift) {
882                         new_start = max_framepos;
883                 } else {
884                         new_start = _start + start_shift;
885                 }
886
887         } else if (start_shift < 0) {
888
889                 if (_start < -start_shift && !can_trim_start_before_source_start ()) {
890                         new_start = 0;
891                 } else {
892                         new_start = _start + start_shift;
893                 }
894
895         } else {
896                 new_start = _start;
897         }
898
899         if (!verify_start_and_length (new_start, length)) {
900                 return;
901         }
902
903         PropertyChange what_changed;
904
905         if (_start != new_start) {
906                 _start = new_start;
907                 what_changed.add (Properties::start);
908         }
909
910         /* Set position before length, otherwise for MIDI regions this bad thing happens:
911          * 1. we call set_length_internal; length in beats is computed using the region's current
912          *    (soon-to-be old) position
913          * 2. we call set_position_internal; position is set and length in frames re-computed using
914          *    length in beats from (1) but at the new position, which is wrong if the region
915          *    straddles a tempo/meter change.
916          */
917
918         if (_position != position) {
919                 if (!property_changes_suspended()) {
920                         _last_position = _position;
921                 }
922                 set_position_internal (position, true);
923                 what_changed.add (Properties::position);
924         }
925
926         if (_length != length) {
927                 if (!property_changes_suspended()) {
928                         _last_length = _length;
929                 }
930                 set_length_internal (length);
931                 what_changed.add (Properties::length);
932         }
933
934         _whole_file = false;
935
936         PropertyChange start_and_length;
937
938         start_and_length.add (Properties::start);
939         start_and_length.add (Properties::length);
940
941         if (what_changed.contains (start_and_length)) {
942                 first_edit ();
943         }
944
945         if (!what_changed.empty()) {
946                 send_change (what_changed);
947         }
948 }
949
950 void
951 Region::set_hidden (bool yn)
952 {
953         if (hidden() != yn) {
954                 _hidden = yn;
955                 send_change (Properties::hidden);
956         }
957 }
958
959 void
960 Region::set_whole_file (bool yn)
961 {
962         _whole_file = yn;
963         /* no change signal */
964 }
965
966 void
967 Region::set_automatic (bool yn)
968 {
969         _automatic = yn;
970         /* no change signal */
971 }
972
973 void
974 Region::set_muted (bool yn)
975 {
976         if (muted() != yn) {
977                 _muted = yn;
978                 send_change (Properties::muted);
979         }
980 }
981
982 void
983 Region::set_opaque (bool yn)
984 {
985         if (opaque() != yn) {
986                 _opaque = yn;
987                 send_change (Properties::opaque);
988         }
989 }
990
991 void
992 Region::set_locked (bool yn)
993 {
994         if (locked() != yn) {
995                 _locked = yn;
996                 send_change (Properties::locked);
997         }
998 }
999
1000 void
1001 Region::set_position_locked (bool yn)
1002 {
1003         if (position_locked() != yn) {
1004                 _position_locked = yn;
1005                 send_change (Properties::locked);
1006         }
1007 }
1008
1009 /** Set the region's sync point.
1010  *  @param absolute_pos Session time.
1011  */
1012 void
1013 Region::set_sync_position (framepos_t absolute_pos)
1014 {
1015         /* position within our file */
1016         framepos_t const file_pos = _start + (absolute_pos - _position);
1017
1018         if (file_pos != _sync_position) {
1019                 _sync_marked = true;
1020                 _sync_position = file_pos;
1021                 if (!property_changes_suspended()) {
1022                         maybe_uncopy ();
1023                 }
1024
1025                 send_change (Properties::sync_position);
1026         }
1027 }
1028
1029 void
1030 Region::clear_sync_position ()
1031 {
1032         if (sync_marked()) {
1033                 _sync_marked = false;
1034                 if (!property_changes_suspended()) {
1035                         maybe_uncopy ();
1036                 }
1037
1038                 send_change (Properties::sync_position);
1039         }
1040 }
1041
1042 /* @return the sync point relative the first frame of the region */
1043 frameoffset_t
1044 Region::sync_offset (int& dir) const
1045 {
1046         if (sync_marked()) {
1047                 if (_sync_position > _start) {
1048                         dir = 1;
1049                         return _sync_position - _start;
1050                 } else {
1051                         dir = -1;
1052                         return _start - _sync_position;
1053                 }
1054         } else {
1055                 dir = 0;
1056                 return 0;
1057         }
1058 }
1059
1060 framepos_t
1061 Region::adjust_to_sync (framepos_t pos) const
1062 {
1063         int sync_dir;
1064         frameoffset_t offset = sync_offset (sync_dir);
1065
1066         // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1067
1068         if (sync_dir > 0) {
1069                 if (pos > offset) {
1070                         pos -= offset;
1071                 } else {
1072                         pos = 0;
1073                 }
1074         } else {
1075                 if (max_framepos - pos > offset) {
1076                         pos += offset;
1077                 }
1078         }
1079
1080         return pos;
1081 }
1082
1083 /** @return Sync position in session time */
1084 framepos_t
1085 Region::sync_position() const
1086 {
1087         if (sync_marked()) {
1088                 return _position - _start + _sync_position;
1089         } else {
1090                 /* if sync has not been marked, use the start of the region */
1091                 return _position;
1092         }
1093 }
1094
1095 void
1096 Region::raise ()
1097 {
1098         boost::shared_ptr<Playlist> pl (playlist());
1099         if (pl) {
1100                 pl->raise_region (shared_from_this ());
1101         }
1102 }
1103
1104 void
1105 Region::lower ()
1106 {
1107         boost::shared_ptr<Playlist> pl (playlist());
1108         if (pl) {
1109                 pl->lower_region (shared_from_this ());
1110         }
1111 }
1112
1113
1114 void
1115 Region::raise_to_top ()
1116 {
1117         boost::shared_ptr<Playlist> pl (playlist());
1118         if (pl) {
1119                 pl->raise_region_to_top (shared_from_this());
1120         }
1121 }
1122
1123 void
1124 Region::lower_to_bottom ()
1125 {
1126         boost::shared_ptr<Playlist> pl (playlist());
1127         if (pl) {
1128                 pl->lower_region_to_bottom (shared_from_this());
1129         }
1130 }
1131
1132 void
1133 Region::set_layer (layer_t l)
1134 {
1135         if (_layer != l) {
1136                 _layer = l;
1137                 send_change (Properties::layer);
1138         }
1139
1140         Evoral::Range<framepos_t> const b = bounds ();
1141         _last_relayer_bounds_from = b.from;
1142         _last_relayer_bounds_to = b.to;
1143 }
1144
1145 XMLNode&
1146 Region::state ()
1147 {
1148         XMLNode *node = new XMLNode ("Region");
1149         char buf[64];
1150         char buf2[64];
1151         LocaleGuard lg (X_("POSIX"));
1152         const char* fe = NULL;
1153
1154         add_properties (*node);
1155
1156         id().print (buf, sizeof (buf));
1157         node->add_property ("id", buf);
1158         node->add_property ("type", _type.to_string());
1159
1160         switch (_first_edit) {
1161         case EditChangesNothing:
1162                 fe = X_("nothing");
1163                 break;
1164         case EditChangesName:
1165                 fe = X_("name");
1166                 break;
1167         case EditChangesID:
1168                 fe = X_("id");
1169                 break;
1170         default: /* should be unreachable but makes g++ happy */
1171                 fe = X_("nothing");
1172                 break;
1173         }
1174
1175         node->add_property ("first-edit", fe);
1176
1177         /* note: flags are stored by derived classes */
1178
1179         if (_position_lock_style != AudioTime) {
1180                 stringstream str;
1181                 str << _bbt_time;
1182                 node->add_property ("bbt-position", str.str());
1183         }
1184
1185         for (uint32_t n=0; n < _sources.size(); ++n) {
1186                 snprintf (buf2, sizeof(buf2), "source-%d", n);
1187                 _sources[n]->id().print (buf, sizeof(buf));
1188                 node->add_property (buf2, buf);
1189         }
1190
1191         for (uint32_t n=0; n < _master_sources.size(); ++n) {
1192                 snprintf (buf2, sizeof(buf2), "master-source-%d", n);
1193                 _master_sources[n]->id().print (buf, sizeof (buf));
1194                 node->add_property (buf2, buf);
1195         }
1196
1197         /* Only store nested sources for the whole-file region that acts
1198            as the parent/root of all regions using it.
1199         */
1200
1201         if (_whole_file && max_source_level() > 0) {
1202
1203                 XMLNode* nested_node = new XMLNode (X_("NestedSource"));
1204
1205                 /* region is compound - get its playlist and
1206                    store that before we list the region that
1207                    needs it ...
1208                 */
1209
1210                 for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) {
1211                         nested_node->add_child_nocopy ((*s)->get_state ());
1212                 }
1213
1214                 if (nested_node) {
1215                         node->add_child_nocopy (*nested_node);
1216                 }
1217         }
1218
1219         if (_extra_xml) {
1220                 node->add_child_copy (*_extra_xml);
1221         }
1222
1223         return *node;
1224 }
1225
1226 XMLNode&
1227 Region::get_state ()
1228 {
1229         return state ();
1230 }
1231
1232 int
1233 Region::set_state (const XMLNode& node, int version)
1234 {
1235         PropertyChange what_changed;
1236         return _set_state (node, version, what_changed, true);
1237 }
1238
1239 int
1240 Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
1241 {
1242         const XMLProperty* prop;
1243
1244         Stateful::save_extra_xml (node);
1245
1246         what_changed = set_values (node);
1247
1248         set_id (node);
1249
1250         if (_position_lock_style == MusicTime) {
1251                 if ((prop = node.property ("bbt-position")) == 0) {
1252                         /* missing BBT info, revert to audio time locking */
1253                         _position_lock_style = AudioTime;
1254                 } else {
1255                         if (sscanf (prop->value().c_str(), "%d|%d|%d",
1256                                     &_bbt_time.bars,
1257                                     &_bbt_time.beats,
1258                                     &_bbt_time.ticks) != 3) {
1259                                 _position_lock_style = AudioTime;
1260                         }
1261                 }
1262         }
1263
1264         /* fix problems with old sessions corrupted by impossible
1265            values for _stretch or _shift
1266         */
1267         if (_stretch == 0.0f) {
1268                 _stretch = 1.0f;
1269         }
1270
1271         if (_shift == 0.0f) {
1272                 _shift = 1.0f;
1273         }
1274
1275         if (send) {
1276                 send_change (what_changed);
1277         }
1278
1279         /* Quick fix for 2.x sessions when region is muted */
1280         if ((prop = node.property (X_("flags")))) {
1281                 if (string::npos != prop->value().find("Muted")){
1282                         set_muted (true);
1283                 }
1284         }
1285
1286
1287         return 0;
1288 }
1289
1290 void
1291 Region::suspend_property_changes ()
1292 {
1293         Stateful::suspend_property_changes ();
1294         _last_length = _length;
1295         _last_position = _position;
1296 }
1297
1298 void
1299 Region::mid_thaw (const PropertyChange& what_changed)
1300 {
1301         if (what_changed.contains (Properties::length)) {
1302                 if (what_changed.contains (Properties::position)) {
1303                         recompute_at_start ();
1304                 }
1305                 recompute_at_end ();
1306         }
1307 }
1308
1309 void
1310 Region::send_change (const PropertyChange& what_changed)
1311 {
1312         if (what_changed.empty()) {
1313                 return;
1314         }
1315
1316         Stateful::send_change (what_changed);
1317
1318         if (!Stateful::property_changes_suspended()) {
1319
1320                 /* Try and send a shared_pointer unless this is part of the constructor.
1321                    If so, do nothing.
1322                 */
1323
1324                 try {
1325                         boost::shared_ptr<Region> rptr = shared_from_this();
1326                         RegionPropertyChanged (rptr, what_changed);
1327                 } catch (...) {
1328                         /* no shared_ptr available, relax; */
1329                 }
1330         }
1331 }
1332
1333 void
1334 Region::set_last_layer_op (LayerOp op, uint64_t when)
1335 {
1336         switch (op) {
1337         case LayerOpAdd:
1338                 _last_layer_op_add = when;
1339                 break;
1340         case LayerOpBoundsChange:
1341                 _last_layer_op_bounds_change = when;
1342                 break;
1343         }
1344 }
1345
1346 bool
1347 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1348 {
1349         return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1350 }
1351
1352 bool
1353 Region::equivalent (boost::shared_ptr<const Region> other) const
1354 {
1355         return _start == other->_start &&
1356                 _position == other->_position &&
1357                 _length == other->_length;
1358 }
1359
1360 bool
1361 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1362 {
1363         return _start == other->_start &&
1364                 _length == other->_length;
1365 }
1366
1367 bool
1368 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1369 {
1370         return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1371 }
1372
1373 void
1374 Region::source_deleted (boost::weak_ptr<Source>)
1375 {
1376         drop_sources ();
1377
1378         if (!_session.deletion_in_progress()) {
1379                 /* this is a very special case: at least one of the region's
1380                    sources has bee deleted, so invalidate all references to
1381                    ourselves. Do NOT do this during session deletion, because
1382                    then we run the risk that this will actually result
1383                    in this object being deleted (as refcnt goes to zero)
1384                    while emitting DropReferences.
1385                 */
1386
1387                 drop_references ();
1388         }
1389 }
1390
1391 vector<string>
1392 Region::master_source_names ()
1393 {
1394         SourceList::iterator i;
1395
1396         vector<string> names;
1397         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1398                 names.push_back((*i)->name());
1399         }
1400
1401         return names;
1402 }
1403
1404 void
1405 Region::set_master_sources (const SourceList& srcs)
1406 {
1407         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1408                 (*i)->dec_use_count ();
1409         }
1410
1411         _master_sources = srcs;
1412         assert (_sources.size() == _master_sources.size());
1413
1414         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1415                 (*i)->inc_use_count ();
1416         }
1417 }
1418
1419 bool
1420 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1421 {
1422         if (!other)
1423                 return false;
1424
1425         if ((_sources.size() != other->_sources.size()) ||
1426             (_master_sources.size() != other->_master_sources.size())) {
1427                 return false;
1428         }
1429
1430         SourceList::const_iterator i;
1431         SourceList::const_iterator io;
1432
1433         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1434                 if ((*i)->id() != (*io)->id()) {
1435                         return false;
1436                 }
1437         }
1438
1439         for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1440                 if ((*i)->id() != (*io)->id()) {
1441                         return false;
1442                 }
1443         }
1444
1445         return true;
1446 }
1447
1448 std::string
1449 Region::source_string () const
1450 {
1451         //string res = itos(_sources.size());
1452
1453         stringstream res;
1454         res << _sources.size() << ":";
1455
1456         SourceList::const_iterator i;
1457
1458         for (i = _sources.begin(); i != _sources.end(); ++i) {
1459                 res << (*i)->id() << ":";
1460         }
1461
1462         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1463                 res << (*i)->id() << ":";
1464         }
1465
1466         return res.str();
1467 }
1468
1469 bool
1470 Region::uses_source (boost::shared_ptr<const Source> source) const
1471 {
1472         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1473                 if (*i == source) {
1474                         return true;
1475                 }
1476
1477                 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1478
1479                 if (ps) {
1480                         if (ps->playlist()->uses_source (source)) {
1481                                 return true;
1482                         }
1483                 }
1484         }
1485
1486         return false;
1487 }
1488
1489 framecnt_t
1490 Region::source_length(uint32_t n) const
1491 {
1492         assert (n < _sources.size());
1493         return _sources[n]->length (_position - _start);
1494 }
1495
1496 bool
1497 Region::verify_length (framecnt_t len)
1498 {
1499         if (source() && (source()->destructive() || source()->length_mutable())) {
1500                 return true;
1501         }
1502
1503         framecnt_t maxlen = 0;
1504
1505         for (uint32_t n = 0; n < _sources.size(); ++n) {
1506                 maxlen = max (maxlen, source_length(n) - _start);
1507         }
1508
1509         len = min (len, maxlen);
1510
1511         return true;
1512 }
1513
1514 bool
1515 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1516 {
1517         if (source() && (source()->destructive() || source()->length_mutable())) {
1518                 return true;
1519         }
1520
1521         framecnt_t maxlen = 0;
1522
1523         for (uint32_t n = 0; n < _sources.size(); ++n) {
1524                 maxlen = max (maxlen, source_length(n) - new_start);
1525         }
1526
1527         new_length = min (new_length, maxlen);
1528
1529         return true;
1530 }
1531
1532 bool
1533 Region::verify_start (framepos_t pos)
1534 {
1535         if (source() && (source()->destructive() || source()->length_mutable())) {
1536                 return true;
1537         }
1538
1539         for (uint32_t n = 0; n < _sources.size(); ++n) {
1540                 if (pos > source_length(n) - _length) {
1541                         return false;
1542                 }
1543         }
1544         return true;
1545 }
1546
1547 bool
1548 Region::verify_start_mutable (framepos_t& new_start)
1549 {
1550         if (source() && (source()->destructive() || source()->length_mutable())) {
1551                 return true;
1552         }
1553
1554         for (uint32_t n = 0; n < _sources.size(); ++n) {
1555                 if (new_start > source_length(n) - _length) {
1556                         new_start = source_length(n) - _length;
1557                 }
1558         }
1559         return true;
1560 }
1561
1562 boost::shared_ptr<Region>
1563 Region::get_parent() const
1564 {
1565         boost::shared_ptr<Playlist> pl (playlist());
1566
1567         if (pl) {
1568                 boost::shared_ptr<Region> r;
1569                 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1570
1571                 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1572                         return boost::static_pointer_cast<Region> (r);
1573                 }
1574         }
1575
1576         return boost::shared_ptr<Region>();
1577 }
1578
1579 int
1580 Region::apply (Filter& filter, Progress* progress)
1581 {
1582         return filter.run (shared_from_this(), progress);
1583 }
1584
1585
1586 void
1587 Region::invalidate_transients ()
1588 {
1589         _valid_transients = false;
1590         _transients.clear ();
1591
1592         send_change (PropertyChange (Properties::valid_transients));
1593 }
1594
1595 void
1596 Region::drop_sources ()
1597 {
1598         for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1599                 (*i)->dec_use_count ();
1600         }
1601
1602         _sources.clear ();
1603
1604         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1605                 (*i)->dec_use_count ();
1606         }
1607
1608         _master_sources.clear ();
1609 }
1610
1611 void
1612 Region::use_sources (SourceList const & s)
1613 {
1614         set<boost::shared_ptr<Source> > unique_srcs;
1615
1616         for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1617
1618                 _sources.push_back (*i);
1619                 (*i)->inc_use_count ();
1620                 _master_sources.push_back (*i);
1621                 (*i)->inc_use_count ();
1622
1623                 /* connect only once to DropReferences, even if sources are replicated
1624                  */
1625
1626                 if (unique_srcs.find (*i) == unique_srcs.end ()) {
1627                         unique_srcs.insert (*i);
1628                         (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1629                 }
1630         }
1631 }
1632
1633 Trimmable::CanTrim
1634 Region::can_trim () const
1635 {
1636         CanTrim ct = CanTrim (0);
1637
1638         if (locked()) {
1639                 return ct;
1640         }
1641
1642         /* if not locked, we can always move the front later, and the end earlier
1643          */
1644
1645         ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
1646
1647         if (start() != 0 || can_trim_start_before_source_start ()) {
1648                 ct = CanTrim (ct | FrontTrimEarlier);
1649         }
1650
1651         if (!_sources.empty()) {
1652                 if ((start() + length()) < _sources.front()->length (0)) {
1653                         ct = CanTrim (ct | EndTrimLater);
1654                 }
1655         }
1656
1657         return ct;
1658 }
1659
1660 uint32_t
1661 Region::max_source_level () const
1662 {
1663         uint32_t lvl = 0;
1664
1665         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1666                 lvl = max (lvl, (*i)->level());
1667         }
1668
1669         return lvl;
1670 }
1671
1672 bool
1673 Region::is_compound () const
1674 {
1675         return max_source_level() > 0;
1676 }
1677
1678 void
1679 Region::post_set (const PropertyChange& pc)
1680 {
1681         if (pc.contains (Properties::position)) {
1682                 recompute_position_from_lock_style ();
1683         }
1684 }
1685
1686 uint64_t
1687 Region::last_layer_op (LayerOp op) const
1688 {
1689         switch (op) {
1690         case LayerOpAdd:
1691                 return _last_layer_op_add;
1692         case LayerOpBoundsChange:
1693                 return _last_layer_op_bounds_change;
1694         }
1695
1696         /* NOTREACHED */
1697         return 0;
1698 }
1699
1700 Evoral::Range<framepos_t>
1701 Region::bounds () const
1702 {
1703         return Evoral::Range<framepos_t> (_position, _position + _length);
1704 }
1705
1706