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