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