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