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