Tempo ramps - fix save/restore of region position_lock_style.
[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                         _beat = _session.tempo_map().beat_at_frame (_position);
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         TempoMap& map (_session.tempo_map());
557         framepos_t pos = map.frame_at_beat (_beat);
558         set_position_internal (pos, false);
559
560         /* do this even if the position is the same. this helps out
561            a GUI that has moved its representation already.
562         */
563         send_change (Properties::position);
564 }
565
566 void
567 Region::set_position (framepos_t pos)
568 {
569         if (!can_move()) {
570                 return;
571         }
572
573         set_position_internal (pos, true);
574
575         /* do this even if the position is the same. this helps out
576            a GUI that has moved its representation already.
577         */
578         send_change (Properties::position);
579
580 }
581
582 /** A gui may need to create a region, then place it in an initial
583  *  position determined by the user.
584  *  When this takes place within one gui operation, we have to reset
585  *  _last_position to prevent an implied move.
586  */
587 void
588 Region::set_initial_position (framepos_t pos)
589 {
590         if (!can_move()) {
591                 return;
592         }
593
594         if (_position != pos) {
595                 _position = pos;
596
597                 /* check that the new _position wouldn't make the current
598                    length impossible - if so, change the length.
599
600                    XXX is this the right thing to do?
601                 */
602
603                 if (max_framepos - _length < _position) {
604                         _last_length = _length;
605                         _length = max_framepos - _position;
606                 }
607
608                 recompute_position_from_lock_style ();
609                 /* ensure that this move doesn't cause a range move */
610                 _last_position = _position;
611         }
612
613
614         /* do this even if the position is the same. this helps out
615            a GUI that has moved its representation already.
616         */
617         send_change (Properties::position);
618 }
619
620 void
621 Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
622 {
623         /* We emit a change of Properties::position even if the position hasn't changed
624            (see Region::set_position), so we must always set this up so that
625            e.g. Playlist::notify_region_moved doesn't use an out-of-date last_position.
626         */
627         _last_position = _position;
628
629         if (_position != pos) {
630                 _position = pos;
631
632                 /* check that the new _position wouldn't make the current
633                    length impossible - if so, change the length.
634
635                    XXX is this the right thing to do?
636                 */
637
638                 if (max_framepos - _length < _position) {
639                         _last_length = _length;
640                         _length = max_framepos - _position;
641                 }
642
643                 if (allow_bbt_recompute) {
644                         recompute_position_from_lock_style ();
645                 }
646         }
647 }
648
649 void
650 Region::recompute_position_from_lock_style ()
651 {
652         if (_position_lock_style == MusicTime) {
653                 _beat = _session.tempo_map().beat_at_frame (_position);
654         }
655 }
656
657 void
658 Region::nudge_position (frameoffset_t n)
659 {
660         if (locked() || video_locked()) {
661                 return;
662         }
663
664         if (n == 0) {
665                 return;
666         }
667
668         framepos_t new_position = _position;
669
670         if (n > 0) {
671                 if (_position > max_framepos - n) {
672                         new_position = max_framepos;
673                 } else {
674                         new_position += n;
675                 }
676         } else {
677                 if (_position < -n) {
678                         new_position = 0;
679                 } else {
680                         new_position += n;
681                 }
682         }
683
684         set_position_internal (new_position, true);
685
686         send_change (Properties::position);
687 }
688
689 void
690 Region::set_ancestral_data (framepos_t s, framecnt_t l, float st, float sh)
691 {
692         _ancestral_length = l;
693         _ancestral_start = s;
694         _stretch = st;
695         _shift = sh;
696 }
697
698 void
699 Region::set_start (framepos_t pos)
700 {
701         if (locked() || position_locked() || video_locked()) {
702                 return;
703         }
704         /* This just sets the start, nothing else. It effectively shifts
705            the contents of the Region within the overall extent of the Source,
706            without changing the Region's position or length
707         */
708
709         if (_start != pos) {
710
711                 if (!verify_start (pos)) {
712                         return;
713                 }
714
715                 set_start_internal (pos);
716                 _whole_file = false;
717                 first_edit ();
718                 maybe_invalidate_transients ();
719
720                 send_change (Properties::start);
721         }
722 }
723
724 void
725 Region::move_start (frameoffset_t distance)
726 {
727         if (locked() || position_locked() || video_locked()) {
728                 return;
729         }
730
731         framepos_t new_start;
732
733         if (distance > 0) {
734
735                 if (_start > max_framepos - distance) {
736                         new_start = max_framepos; // makes no sense
737                 } else {
738                         new_start = _start + distance;
739                 }
740
741                 if (!verify_start (new_start)) {
742                         return;
743                 }
744
745         } else if (distance < 0) {
746
747                 if (_start < -distance) {
748                         new_start = 0;
749                 } else {
750                         new_start = _start + distance;
751                 }
752
753         } else {
754                 return;
755         }
756
757         if (new_start == _start) {
758                 return;
759         }
760
761         set_start_internal (new_start);
762
763         _whole_file = false;
764         first_edit ();
765
766         send_change (Properties::start);
767 }
768
769 void
770 Region::trim_front (framepos_t new_position)
771 {
772         modify_front (new_position, false);
773 }
774
775 void
776 Region::cut_front (framepos_t new_position)
777 {
778         modify_front (new_position, true);
779 }
780
781 void
782 Region::cut_end (framepos_t new_endpoint)
783 {
784         modify_end (new_endpoint, true);
785 }
786
787 void
788 Region::modify_front (framepos_t new_position, bool reset_fade)
789 {
790         if (locked()) {
791                 return;
792         }
793
794         framepos_t end = last_frame();
795         framepos_t source_zero;
796
797         if (_position > _start) {
798                 source_zero = _position - _start;
799         } else {
800                 source_zero = 0; // its actually negative, but this will work for us
801         }
802
803         if (new_position < end) { /* can't trim it zero or negative length */
804
805                 framecnt_t newlen = 0;
806
807                 if (!can_trim_start_before_source_start ()) {
808                         /* can't trim it back past where source position zero is located */
809                         new_position = max (new_position, source_zero);
810                 }
811
812                 if (new_position > _position) {
813                         newlen = _length - (new_position - _position);
814                 } else {
815                         newlen = _length + (_position - new_position);
816                 }
817
818                 trim_to_internal (new_position, newlen);
819
820                 if (reset_fade) {
821                         _right_of_split = true;
822                 }
823
824                 if (!property_changes_suspended()) {
825                         recompute_at_start ();
826                 }
827
828                 maybe_invalidate_transients ();
829         }
830 }
831
832 void
833 Region::modify_end (framepos_t new_endpoint, bool reset_fade)
834 {
835         if (locked()) {
836                 return;
837         }
838
839         if (new_endpoint > _position) {
840                 trim_to_internal (_position, new_endpoint - _position);
841                 if (reset_fade) {
842                         _left_of_split = true;
843                 }
844                 if (!property_changes_suspended()) {
845                         recompute_at_end ();
846                 }
847         }
848 }
849
850 /** @param new_endpoint New region end point, such that, for example,
851  *  a region at 0 of length 10 has an endpoint of 9.
852  */
853
854 void
855 Region::trim_end (framepos_t new_endpoint)
856 {
857         modify_end (new_endpoint, false);
858 }
859
860 void
861 Region::trim_to (framepos_t position, framecnt_t length)
862 {
863         if (locked()) {
864                 return;
865         }
866
867         trim_to_internal (position, length);
868
869         if (!property_changes_suspended()) {
870                 recompute_at_start ();
871                 recompute_at_end ();
872         }
873 }
874
875 void
876 Region::trim_to_internal (framepos_t position, framecnt_t length)
877 {
878         framepos_t new_start;
879
880         if (locked()) {
881                 return;
882         }
883
884         frameoffset_t const start_shift = position - _position;
885
886         if (start_shift > 0) {
887
888                 if (_start > max_framepos - start_shift) {
889                         new_start = max_framepos;
890                 } else {
891                         new_start = _start + start_shift;
892                 }
893
894         } else if (start_shift < 0) {
895
896                 if (_start < -start_shift && !can_trim_start_before_source_start ()) {
897                         new_start = 0;
898                 } else {
899                         new_start = _start + start_shift;
900                 }
901
902         } else {
903                 new_start = _start;
904         }
905
906         if (!verify_start_and_length (new_start, length)) {
907                 return;
908         }
909
910         PropertyChange what_changed;
911
912         if (_start != new_start) {
913                 set_start_internal (new_start);
914                 what_changed.add (Properties::start);
915         }
916
917         /* Set position before length, otherwise for MIDI regions this bad thing happens:
918          * 1. we call set_length_internal; length in beats is computed using the region's current
919          *    (soon-to-be old) position
920          * 2. we call set_position_internal; position is set and length in frames re-computed using
921          *    length in beats from (1) but at the new position, which is wrong if the region
922          *    straddles a tempo/meter change.
923          */
924
925         if (_position != position) {
926                 if (!property_changes_suspended()) {
927                         _last_position = _position;
928                 }
929                 set_position_internal (position, true);
930                 what_changed.add (Properties::position);
931         }
932
933         if (_length != length) {
934                 if (!property_changes_suspended()) {
935                         _last_length = _length;
936                 }
937                 set_length_internal (length);
938                 what_changed.add (Properties::length);
939         }
940
941         _whole_file = false;
942
943         PropertyChange start_and_length;
944
945         start_and_length.add (Properties::start);
946         start_and_length.add (Properties::length);
947
948         if (what_changed.contains (start_and_length)) {
949                 first_edit ();
950         }
951
952         if (!what_changed.empty()) {
953                 send_change (what_changed);
954         }
955 }
956
957 void
958 Region::set_hidden (bool yn)
959 {
960         if (hidden() != yn) {
961                 _hidden = yn;
962                 send_change (Properties::hidden);
963         }
964 }
965
966 void
967 Region::set_whole_file (bool yn)
968 {
969         _whole_file = yn;
970         /* no change signal */
971 }
972
973 void
974 Region::set_automatic (bool yn)
975 {
976         _automatic = yn;
977         /* no change signal */
978 }
979
980 void
981 Region::set_muted (bool yn)
982 {
983         if (muted() != yn) {
984                 _muted = yn;
985                 send_change (Properties::muted);
986         }
987 }
988
989 void
990 Region::set_opaque (bool yn)
991 {
992         if (opaque() != yn) {
993                 _opaque = yn;
994                 send_change (Properties::opaque);
995         }
996 }
997
998 void
999 Region::set_locked (bool yn)
1000 {
1001         if (locked() != yn) {
1002                 _locked = yn;
1003                 send_change (Properties::locked);
1004         }
1005 }
1006
1007 void
1008 Region::set_video_locked (bool yn)
1009 {
1010         if (video_locked() != yn) {
1011                 _video_locked = yn;
1012                 send_change (Properties::video_locked);
1013         }
1014 }
1015
1016 void
1017 Region::set_position_locked (bool yn)
1018 {
1019         if (position_locked() != yn) {
1020                 _position_locked = yn;
1021                 send_change (Properties::locked);
1022         }
1023 }
1024
1025 /** Set the region's sync point.
1026  *  @param absolute_pos Session time.
1027  */
1028 void
1029 Region::set_sync_position (framepos_t absolute_pos)
1030 {
1031         /* position within our file */
1032         framepos_t const file_pos = _start + (absolute_pos - _position);
1033
1034         if (file_pos != _sync_position) {
1035                 _sync_marked = true;
1036                 _sync_position = file_pos;
1037                 if (!property_changes_suspended()) {
1038                         maybe_uncopy ();
1039                 }
1040
1041                 send_change (Properties::sync_position);
1042         }
1043 }
1044
1045 void
1046 Region::clear_sync_position ()
1047 {
1048         if (sync_marked()) {
1049                 _sync_marked = false;
1050                 if (!property_changes_suspended()) {
1051                         maybe_uncopy ();
1052                 }
1053
1054                 send_change (Properties::sync_position);
1055         }
1056 }
1057
1058 /* @return the sync point relative the first frame of the region */
1059 frameoffset_t
1060 Region::sync_offset (int& dir) const
1061 {
1062         if (sync_marked()) {
1063                 if (_sync_position > _start) {
1064                         dir = 1;
1065                         return _sync_position - _start;
1066                 } else {
1067                         dir = -1;
1068                         return _start - _sync_position;
1069                 }
1070         } else {
1071                 dir = 0;
1072                 return 0;
1073         }
1074 }
1075
1076 framepos_t
1077 Region::adjust_to_sync (framepos_t pos) const
1078 {
1079         int sync_dir;
1080         frameoffset_t offset = sync_offset (sync_dir);
1081
1082         // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1083
1084         if (sync_dir > 0) {
1085                 if (pos > offset) {
1086                         pos -= offset;
1087                 } else {
1088                         pos = 0;
1089                 }
1090         } else {
1091                 if (max_framepos - pos > offset) {
1092                         pos += offset;
1093                 }
1094         }
1095
1096         return pos;
1097 }
1098
1099 /** @return Sync position in session time */
1100 framepos_t
1101 Region::sync_position() const
1102 {
1103         if (sync_marked()) {
1104                 return _position - _start + _sync_position;
1105         } else {
1106                 /* if sync has not been marked, use the start of the region */
1107                 return _position;
1108         }
1109 }
1110
1111 void
1112 Region::raise ()
1113 {
1114         boost::shared_ptr<Playlist> pl (playlist());
1115         if (pl) {
1116                 pl->raise_region (shared_from_this ());
1117         }
1118 }
1119
1120 void
1121 Region::lower ()
1122 {
1123         boost::shared_ptr<Playlist> pl (playlist());
1124         if (pl) {
1125                 pl->lower_region (shared_from_this ());
1126         }
1127 }
1128
1129
1130 void
1131 Region::raise_to_top ()
1132 {
1133         boost::shared_ptr<Playlist> pl (playlist());
1134         if (pl) {
1135                 pl->raise_region_to_top (shared_from_this());
1136         }
1137 }
1138
1139 void
1140 Region::lower_to_bottom ()
1141 {
1142         boost::shared_ptr<Playlist> pl (playlist());
1143         if (pl) {
1144                 pl->lower_region_to_bottom (shared_from_this());
1145         }
1146 }
1147
1148 void
1149 Region::set_layer (layer_t l)
1150 {
1151         _layer = l;
1152 }
1153
1154 XMLNode&
1155 Region::state ()
1156 {
1157         XMLNode *node = new XMLNode ("Region");
1158         char buf[64];
1159         char buf2[64];
1160         LocaleGuard lg;
1161         const char* fe = NULL;
1162
1163         /* custom version of 'add_properties (*node);'
1164          * skip values that have have dedicated save functions
1165          * in AudioRegion::state()
1166          */
1167         for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
1168                 if (!strcmp(i->second->property_name(), (const char*)"Envelope")) continue;
1169                 if (!strcmp(i->second->property_name(), (const char*)"FadeIn")) continue;
1170                 if (!strcmp(i->second->property_name(), (const char*)"FadeOut")) continue;
1171                 if (!strcmp(i->second->property_name(), (const char*)"InverseFadeIn")) continue;
1172                 if (!strcmp(i->second->property_name(), (const char*)"InverseFadeOut")) continue;
1173                 i->second->get_value (*node);
1174         }
1175
1176         id().print (buf, sizeof (buf));
1177         node->add_property ("id", buf);
1178         node->add_property ("type", _type.to_string());
1179
1180         switch (_first_edit) {
1181         case EditChangesNothing:
1182                 fe = X_("nothing");
1183                 break;
1184         case EditChangesName:
1185                 fe = X_("name");
1186                 break;
1187         case EditChangesID:
1188                 fe = X_("id");
1189                 break;
1190         default: /* should be unreachable but makes g++ happy */
1191                 fe = X_("nothing");
1192                 break;
1193         }
1194
1195         node->add_property ("first-edit", fe);
1196
1197         /* note: flags are stored by derived classes */
1198
1199         if (_position_lock_style != AudioTime) {
1200                 snprintf (buf, sizeof(buf), "%lf", _beat);
1201                 node->add_property ("beat", buf);
1202         }
1203
1204         for (uint32_t n=0; n < _sources.size(); ++n) {
1205                 snprintf (buf2, sizeof(buf2), "source-%d", n);
1206                 _sources[n]->id().print (buf, sizeof(buf));
1207                 node->add_property (buf2, buf);
1208         }
1209
1210         for (uint32_t n=0; n < _master_sources.size(); ++n) {
1211                 snprintf (buf2, sizeof(buf2), "master-source-%d", n);
1212                 _master_sources[n]->id().print (buf, sizeof (buf));
1213                 node->add_property (buf2, buf);
1214         }
1215
1216         /* Only store nested sources for the whole-file region that acts
1217            as the parent/root of all regions using it.
1218         */
1219
1220         if (_whole_file && max_source_level() > 0) {
1221
1222                 XMLNode* nested_node = new XMLNode (X_("NestedSource"));
1223
1224                 /* region is compound - get its playlist and
1225                    store that before we list the region that
1226                    needs it ...
1227                 */
1228
1229                 for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) {
1230                         nested_node->add_child_nocopy ((*s)->get_state ());
1231                 }
1232
1233                 if (nested_node) {
1234                         node->add_child_nocopy (*nested_node);
1235                 }
1236         }
1237
1238         if (_extra_xml) {
1239                 node->add_child_copy (*_extra_xml);
1240         }
1241
1242         return *node;
1243 }
1244
1245 XMLNode&
1246 Region::get_state ()
1247 {
1248         return state ();
1249 }
1250
1251 int
1252 Region::set_state (const XMLNode& node, int version)
1253 {
1254         PropertyChange what_changed;
1255         return _set_state (node, version, what_changed, true);
1256 }
1257
1258 int
1259 Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
1260 {
1261         XMLProperty const * prop;
1262         Timecode::BBT_Time bbt_time;
1263
1264         Stateful::save_extra_xml (node);
1265
1266         what_changed = set_values (node);
1267
1268         set_id (node);
1269
1270         if (_position_lock_style == MusicTime) {
1271                 if ((prop = node.property ("bbt-position")) == 0) {
1272                         if ((prop = node.property ("beat")) == 0) {
1273                                 /* missing BBT info, revert to audio time locking */
1274                                 _position_lock_style = AudioTime;
1275                         } else {
1276                                 if (sscanf (prop->value().c_str(), "%lf", &_beat) != 1) {
1277                                         _position_lock_style = AudioTime;
1278                                 }
1279                         }
1280
1281                 } else {
1282                         if (sscanf (prop->value().c_str(), "%d|%d|%d",
1283                                     &bbt_time.bars,
1284                                     &bbt_time.beats,
1285                                     &bbt_time.ticks) != 3) {
1286                                 _position_lock_style = AudioTime;
1287                         } else {
1288                                 _beat = _session.tempo_map().bbt_to_beats (bbt_time);
1289                         }
1290                 }
1291         }
1292
1293         /* fix problems with old sessions corrupted by impossible
1294            values for _stretch or _shift
1295         */
1296         if (_stretch == 0.0f) {
1297                 _stretch = 1.0f;
1298         }
1299
1300         if (_shift == 0.0f) {
1301                 _shift = 1.0f;
1302         }
1303
1304         if (send) {
1305                 send_change (what_changed);
1306         }
1307
1308         /* Quick fix for 2.x sessions when region is muted */
1309         if ((prop = node.property (X_("flags")))) {
1310                 if (string::npos != prop->value().find("Muted")){
1311                         set_muted (true);
1312                 }
1313         }
1314
1315         // saved property is invalid, region-transients are not saved
1316         if (_user_transients.size() == 0){
1317                 _valid_transients = false;
1318         }
1319
1320         return 0;
1321 }
1322
1323 void
1324 Region::suspend_property_changes ()
1325 {
1326         Stateful::suspend_property_changes ();
1327         _last_length = _length;
1328         _last_position = _position;
1329 }
1330
1331 void
1332 Region::mid_thaw (const PropertyChange& what_changed)
1333 {
1334         if (what_changed.contains (Properties::length)) {
1335                 if (what_changed.contains (Properties::position)) {
1336                         recompute_at_start ();
1337                 }
1338                 recompute_at_end ();
1339         }
1340 }
1341
1342 void
1343 Region::send_change (const PropertyChange& what_changed)
1344 {
1345         if (what_changed.empty()) {
1346                 return;
1347         }
1348
1349         Stateful::send_change (what_changed);
1350
1351         if (!Stateful::property_changes_suspended()) {
1352
1353                 /* Try and send a shared_pointer unless this is part of the constructor.
1354                    If so, do nothing.
1355                 */
1356
1357                 try {
1358                         boost::shared_ptr<Region> rptr = shared_from_this();
1359                         RegionPropertyChanged (rptr, what_changed);
1360                 } catch (...) {
1361                         /* no shared_ptr available, relax; */
1362                 }
1363         }
1364 }
1365
1366 bool
1367 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1368 {
1369         return coverage (other->first_frame(), other->last_frame()) != Evoral::OverlapNone;
1370 }
1371
1372 bool
1373 Region::equivalent (boost::shared_ptr<const Region> other) const
1374 {
1375         return _start == other->_start &&
1376                 _position == other->_position &&
1377                 _length == other->_length;
1378 }
1379
1380 bool
1381 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1382 {
1383         return _start == other->_start &&
1384                 _length == other->_length;
1385 }
1386
1387 bool
1388 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1389 {
1390         return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1391 }
1392
1393 void
1394 Region::source_deleted (boost::weak_ptr<Source>)
1395 {
1396         drop_sources ();
1397
1398         if (!_session.deletion_in_progress()) {
1399                 /* this is a very special case: at least one of the region's
1400                    sources has bee deleted, so invalidate all references to
1401                    ourselves. Do NOT do this during session deletion, because
1402                    then we run the risk that this will actually result
1403                    in this object being deleted (as refcnt goes to zero)
1404                    while emitting DropReferences.
1405                 */
1406
1407                 drop_references ();
1408         }
1409 }
1410
1411 vector<string>
1412 Region::master_source_names ()
1413 {
1414         SourceList::iterator i;
1415
1416         vector<string> names;
1417         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1418                 names.push_back((*i)->name());
1419         }
1420
1421         return names;
1422 }
1423
1424 void
1425 Region::set_master_sources (const SourceList& srcs)
1426 {
1427         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1428                 (*i)->dec_use_count ();
1429         }
1430
1431         _master_sources = srcs;
1432         assert (_sources.size() == _master_sources.size());
1433
1434         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1435                 (*i)->inc_use_count ();
1436         }
1437 }
1438
1439 bool
1440 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1441 {
1442         if (!other)
1443                 return false;
1444
1445         if ((_sources.size() != other->_sources.size()) ||
1446             (_master_sources.size() != other->_master_sources.size())) {
1447                 return false;
1448         }
1449
1450         SourceList::const_iterator i;
1451         SourceList::const_iterator io;
1452
1453         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1454                 if ((*i)->id() != (*io)->id()) {
1455                         return false;
1456                 }
1457         }
1458
1459         for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1460                 if ((*i)->id() != (*io)->id()) {
1461                         return false;
1462                 }
1463         }
1464
1465         return true;
1466 }
1467
1468 bool
1469 Region::any_source_equivalent (boost::shared_ptr<const Region> other) const
1470 {
1471         if (!other) {
1472                 return false;
1473         }
1474
1475         SourceList::const_iterator i;
1476         SourceList::const_iterator io;
1477
1478         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1479                 if ((*i)->id() == (*io)->id()) {
1480                         return true;
1481                 }
1482         }
1483
1484         return false;
1485 }
1486
1487 std::string
1488 Region::source_string () const
1489 {
1490         //string res = itos(_sources.size());
1491
1492         stringstream res;
1493         res << _sources.size() << ":";
1494
1495         SourceList::const_iterator i;
1496
1497         for (i = _sources.begin(); i != _sources.end(); ++i) {
1498                 res << (*i)->id() << ":";
1499         }
1500
1501         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1502                 res << (*i)->id() << ":";
1503         }
1504
1505         return res.str();
1506 }
1507
1508 bool
1509 Region::uses_source (boost::shared_ptr<const Source> source) const
1510 {
1511         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1512                 if (*i == source) {
1513                         return true;
1514                 }
1515
1516                 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1517
1518                 if (ps) {
1519                         if (ps->playlist()->uses_source (source)) {
1520                                 return true;
1521                         }
1522                 }
1523         }
1524
1525         for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1526                 if (*i == source) {
1527                         return true;
1528                 }
1529
1530                 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1531
1532                 if (ps) {
1533                         if (ps->playlist()->uses_source (source)) {
1534                                 return true;
1535                         }
1536                 }
1537         }
1538
1539         return false;
1540 }
1541
1542 framecnt_t
1543 Region::source_length(uint32_t n) const
1544 {
1545         assert (n < _sources.size());
1546         return _sources[n]->length (_position - _start);
1547 }
1548
1549 bool
1550 Region::verify_length (framecnt_t& len)
1551 {
1552         if (source() && (source()->destructive() || source()->length_mutable())) {
1553                 return true;
1554         }
1555
1556         framecnt_t maxlen = 0;
1557
1558         for (uint32_t n = 0; n < _sources.size(); ++n) {
1559                 maxlen = max (maxlen, source_length(n) - _start);
1560         }
1561
1562         len = min (len, maxlen);
1563
1564         return true;
1565 }
1566
1567 bool
1568 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1569 {
1570         if (source() && (source()->destructive() || source()->length_mutable())) {
1571                 return true;
1572         }
1573
1574         framecnt_t maxlen = 0;
1575
1576         for (uint32_t n = 0; n < _sources.size(); ++n) {
1577                 maxlen = max (maxlen, source_length(n) - new_start);
1578         }
1579
1580         new_length = min (new_length, maxlen);
1581
1582         return true;
1583 }
1584
1585 bool
1586 Region::verify_start (framepos_t pos)
1587 {
1588         if (source() && (source()->destructive() || source()->length_mutable())) {
1589                 return true;
1590         }
1591
1592         for (uint32_t n = 0; n < _sources.size(); ++n) {
1593                 if (pos > source_length(n) - _length) {
1594                         return false;
1595                 }
1596         }
1597         return true;
1598 }
1599
1600 bool
1601 Region::verify_start_mutable (framepos_t& new_start)
1602 {
1603         if (source() && (source()->destructive() || source()->length_mutable())) {
1604                 return true;
1605         }
1606
1607         for (uint32_t n = 0; n < _sources.size(); ++n) {
1608                 if (new_start > source_length(n) - _length) {
1609                         new_start = source_length(n) - _length;
1610                 }
1611         }
1612         return true;
1613 }
1614
1615 boost::shared_ptr<Region>
1616 Region::get_parent() const
1617 {
1618         boost::shared_ptr<Playlist> pl (playlist());
1619
1620         if (pl) {
1621                 boost::shared_ptr<Region> r;
1622                 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1623
1624                 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1625                         return boost::static_pointer_cast<Region> (r);
1626                 }
1627         }
1628
1629         return boost::shared_ptr<Region>();
1630 }
1631
1632 int
1633 Region::apply (Filter& filter, Progress* progress)
1634 {
1635         return filter.run (shared_from_this(), progress);
1636 }
1637
1638
1639 void
1640 Region::maybe_invalidate_transients ()
1641 {
1642         bool changed = !_onsets.empty();
1643         _onsets.clear ();
1644
1645         if (_valid_transients || changed) {
1646                 send_change (PropertyChange (Properties::valid_transients));
1647                 return;
1648         }
1649 }
1650
1651 void
1652 Region::transients (AnalysisFeatureList& afl)
1653 {
1654         int cnt = afl.empty() ? 0 : 1;
1655
1656         Region::merge_features (afl, _onsets, _position);
1657         Region::merge_features (afl, _user_transients, _position + _transient_user_start - _start);
1658         if (!_onsets.empty ()) {
1659                 ++cnt;
1660         }
1661         if (!_user_transients.empty ()) {
1662                 ++cnt;
1663         }
1664         if (cnt > 1 ) {
1665                 afl.sort ();
1666                 // remove exact duplicates
1667                 TransientDetector::cleanup_transients (afl, _session.frame_rate(), 0);
1668         }
1669 }
1670
1671 bool
1672 Region::has_transients () const
1673 {
1674         if (!_user_transients.empty ()) {
1675                 assert (_valid_transients);
1676                 return true;
1677         }
1678         if (!_onsets.empty ()) {
1679                 return true;
1680         }
1681         return false;
1682 }
1683
1684 void
1685 Region::merge_features (AnalysisFeatureList& result, const AnalysisFeatureList& src, const frameoffset_t off) const
1686 {
1687         for (AnalysisFeatureList::const_iterator x = src.begin(); x != src.end(); ++x) {
1688                 const frameoffset_t p = (*x) + off;
1689                 if (p < first_frame() || p > last_frame()) {
1690                         continue;
1691                 }
1692                 result.push_back (p);
1693         }
1694 }
1695
1696 void
1697 Region::drop_sources ()
1698 {
1699         for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1700                 (*i)->dec_use_count ();
1701         }
1702
1703         _sources.clear ();
1704
1705         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1706                 (*i)->dec_use_count ();
1707         }
1708
1709         _master_sources.clear ();
1710 }
1711
1712 void
1713 Region::use_sources (SourceList const & s)
1714 {
1715         set<boost::shared_ptr<Source> > unique_srcs;
1716
1717         for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1718
1719                 _sources.push_back (*i);
1720                 (*i)->inc_use_count ();
1721                 _master_sources.push_back (*i);
1722                 (*i)->inc_use_count ();
1723
1724                 /* connect only once to DropReferences, even if sources are replicated
1725                  */
1726
1727                 if (unique_srcs.find (*i) == unique_srcs.end ()) {
1728                         unique_srcs.insert (*i);
1729                         (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1730                 }
1731         }
1732 }
1733
1734 Trimmable::CanTrim
1735 Region::can_trim () const
1736 {
1737         CanTrim ct = CanTrim (0);
1738
1739         if (locked()) {
1740                 return ct;
1741         }
1742
1743         /* if not locked, we can always move the front later, and the end earlier
1744          */
1745
1746         ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
1747
1748         if (start() != 0 || can_trim_start_before_source_start ()) {
1749                 ct = CanTrim (ct | FrontTrimEarlier);
1750         }
1751
1752         if (!_sources.empty()) {
1753                 if ((start() + length()) < _sources.front()->length (0)) {
1754                         ct = CanTrim (ct | EndTrimLater);
1755                 }
1756         }
1757
1758         return ct;
1759 }
1760
1761 uint32_t
1762 Region::max_source_level () const
1763 {
1764         uint32_t lvl = 0;
1765
1766         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1767                 lvl = max (lvl, (*i)->level());
1768         }
1769
1770         return lvl;
1771 }
1772
1773 bool
1774 Region::is_compound () const
1775 {
1776         return max_source_level() > 0;
1777 }
1778
1779 void
1780 Region::post_set (const PropertyChange& pc)
1781 {
1782         if (pc.contains (Properties::position)) {
1783                 recompute_position_from_lock_style ();
1784         }
1785 }
1786
1787 void
1788 Region::set_start_internal (framecnt_t s)
1789 {
1790         _start = s;
1791 }
1792
1793 framepos_t
1794 Region::earliest_possible_position () const
1795 {
1796         if (_start > _position) {
1797                 return 0;
1798         } else {
1799                 return _position - _start;
1800         }
1801 }
1802
1803 framecnt_t
1804 Region::latest_possible_frame () const
1805 {
1806         framecnt_t minlen = max_framecnt;
1807
1808         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1809                 /* non-audio regions have a length that may vary based on their
1810                  * position, so we have to pass it in the call.
1811                  */
1812                 minlen = min (minlen, (*i)->length (_position));
1813         }
1814
1815         /* the latest possible last frame is determined by the current
1816          * position, plus the shortest source extent past _start.
1817          */
1818
1819         return _position + (minlen - _start) - 1;
1820 }
1821