Tempo ramps - update midi regions and locations when dragging tempo.
[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                 stringstream str;
1201                 str << _beat;
1202                 node->add_property ("beat", str.str());
1203         }
1204
1205         for (uint32_t n=0; n < _sources.size(); ++n) {
1206                 snprintf (buf2, sizeof(buf2), "source-%d", n);
1207                 _sources[n]->id().print (buf, sizeof(buf));
1208                 node->add_property (buf2, buf);
1209         }
1210
1211         for (uint32_t n=0; n < _master_sources.size(); ++n) {
1212                 snprintf (buf2, sizeof(buf2), "master-source-%d", n);
1213                 _master_sources[n]->id().print (buf, sizeof (buf));
1214                 node->add_property (buf2, buf);
1215         }
1216
1217         /* Only store nested sources for the whole-file region that acts
1218            as the parent/root of all regions using it.
1219         */
1220
1221         if (_whole_file && max_source_level() > 0) {
1222
1223                 XMLNode* nested_node = new XMLNode (X_("NestedSource"));
1224
1225                 /* region is compound - get its playlist and
1226                    store that before we list the region that
1227                    needs it ...
1228                 */
1229
1230                 for (SourceList::const_iterator s = _sources.begin(); s != _sources.end(); ++s) {
1231                         nested_node->add_child_nocopy ((*s)->get_state ());
1232                 }
1233
1234                 if (nested_node) {
1235                         node->add_child_nocopy (*nested_node);
1236                 }
1237         }
1238
1239         if (_extra_xml) {
1240                 node->add_child_copy (*_extra_xml);
1241         }
1242
1243         return *node;
1244 }
1245
1246 XMLNode&
1247 Region::get_state ()
1248 {
1249         return state ();
1250 }
1251
1252 int
1253 Region::set_state (const XMLNode& node, int version)
1254 {
1255         PropertyChange what_changed;
1256         return _set_state (node, version, what_changed, true);
1257 }
1258
1259 int
1260 Region::_set_state (const XMLNode& node, int /*version*/, PropertyChange& what_changed, bool send)
1261 {
1262         XMLProperty const * prop;
1263         Timecode::BBT_Time bbt_time;
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                         _beat = _session.tempo_map().bbt_to_beats (bbt_time);
1283                 }
1284         }
1285
1286         if (_position_lock_style == MusicTime) {
1287                 if ((prop = node.property ("beat")) == 0) {
1288                         /* missing BBT info, revert to audio time locking */
1289                         _position_lock_style = AudioTime;
1290                 } else {
1291                         if (sscanf (prop->value().c_str(), "%lf", &_beat) != 1) {
1292                                 _position_lock_style = AudioTime;
1293                         }
1294                 }
1295         }
1296
1297         /* fix problems with old sessions corrupted by impossible
1298            values for _stretch or _shift
1299         */
1300         if (_stretch == 0.0f) {
1301                 _stretch = 1.0f;
1302         }
1303
1304         if (_shift == 0.0f) {
1305                 _shift = 1.0f;
1306         }
1307
1308         if (send) {
1309                 send_change (what_changed);
1310         }
1311
1312         /* Quick fix for 2.x sessions when region is muted */
1313         if ((prop = node.property (X_("flags")))) {
1314                 if (string::npos != prop->value().find("Muted")){
1315                         set_muted (true);
1316                 }
1317         }
1318
1319         // saved property is invalid, region-transients are not saved
1320         if (_user_transients.size() == 0){
1321                 _valid_transients = false;
1322         }
1323
1324         return 0;
1325 }
1326
1327 void
1328 Region::suspend_property_changes ()
1329 {
1330         Stateful::suspend_property_changes ();
1331         _last_length = _length;
1332         _last_position = _position;
1333 }
1334
1335 void
1336 Region::mid_thaw (const PropertyChange& what_changed)
1337 {
1338         if (what_changed.contains (Properties::length)) {
1339                 if (what_changed.contains (Properties::position)) {
1340                         recompute_at_start ();
1341                 }
1342                 recompute_at_end ();
1343         }
1344 }
1345
1346 void
1347 Region::send_change (const PropertyChange& what_changed)
1348 {
1349         if (what_changed.empty()) {
1350                 return;
1351         }
1352
1353         Stateful::send_change (what_changed);
1354
1355         if (!Stateful::property_changes_suspended()) {
1356
1357                 /* Try and send a shared_pointer unless this is part of the constructor.
1358                    If so, do nothing.
1359                 */
1360
1361                 try {
1362                         boost::shared_ptr<Region> rptr = shared_from_this();
1363                         RegionPropertyChanged (rptr, what_changed);
1364                 } catch (...) {
1365                         /* no shared_ptr available, relax; */
1366                 }
1367         }
1368 }
1369
1370 bool
1371 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1372 {
1373         return coverage (other->first_frame(), other->last_frame()) != Evoral::OverlapNone;
1374 }
1375
1376 bool
1377 Region::equivalent (boost::shared_ptr<const Region> other) const
1378 {
1379         return _start == other->_start &&
1380                 _position == other->_position &&
1381                 _length == other->_length;
1382 }
1383
1384 bool
1385 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1386 {
1387         return _start == other->_start &&
1388                 _length == other->_length;
1389 }
1390
1391 bool
1392 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1393 {
1394         return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1395 }
1396
1397 void
1398 Region::source_deleted (boost::weak_ptr<Source>)
1399 {
1400         drop_sources ();
1401
1402         if (!_session.deletion_in_progress()) {
1403                 /* this is a very special case: at least one of the region's
1404                    sources has bee deleted, so invalidate all references to
1405                    ourselves. Do NOT do this during session deletion, because
1406                    then we run the risk that this will actually result
1407                    in this object being deleted (as refcnt goes to zero)
1408                    while emitting DropReferences.
1409                 */
1410
1411                 drop_references ();
1412         }
1413 }
1414
1415 vector<string>
1416 Region::master_source_names ()
1417 {
1418         SourceList::iterator i;
1419
1420         vector<string> names;
1421         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1422                 names.push_back((*i)->name());
1423         }
1424
1425         return names;
1426 }
1427
1428 void
1429 Region::set_master_sources (const SourceList& srcs)
1430 {
1431         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1432                 (*i)->dec_use_count ();
1433         }
1434
1435         _master_sources = srcs;
1436         assert (_sources.size() == _master_sources.size());
1437
1438         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1439                 (*i)->inc_use_count ();
1440         }
1441 }
1442
1443 bool
1444 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1445 {
1446         if (!other)
1447                 return false;
1448
1449         if ((_sources.size() != other->_sources.size()) ||
1450             (_master_sources.size() != other->_master_sources.size())) {
1451                 return false;
1452         }
1453
1454         SourceList::const_iterator i;
1455         SourceList::const_iterator io;
1456
1457         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1458                 if ((*i)->id() != (*io)->id()) {
1459                         return false;
1460                 }
1461         }
1462
1463         for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1464                 if ((*i)->id() != (*io)->id()) {
1465                         return false;
1466                 }
1467         }
1468
1469         return true;
1470 }
1471
1472 bool
1473 Region::any_source_equivalent (boost::shared_ptr<const Region> other) const
1474 {
1475         if (!other) {
1476                 return false;
1477         }
1478
1479         SourceList::const_iterator i;
1480         SourceList::const_iterator io;
1481
1482         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1483                 if ((*i)->id() == (*io)->id()) {
1484                         return true;
1485                 }
1486         }
1487
1488         return false;
1489 }
1490
1491 std::string
1492 Region::source_string () const
1493 {
1494         //string res = itos(_sources.size());
1495
1496         stringstream res;
1497         res << _sources.size() << ":";
1498
1499         SourceList::const_iterator i;
1500
1501         for (i = _sources.begin(); i != _sources.end(); ++i) {
1502                 res << (*i)->id() << ":";
1503         }
1504
1505         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1506                 res << (*i)->id() << ":";
1507         }
1508
1509         return res.str();
1510 }
1511
1512 bool
1513 Region::uses_source (boost::shared_ptr<const Source> source) const
1514 {
1515         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1516                 if (*i == source) {
1517                         return true;
1518                 }
1519
1520                 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1521
1522                 if (ps) {
1523                         if (ps->playlist()->uses_source (source)) {
1524                                 return true;
1525                         }
1526                 }
1527         }
1528
1529         for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1530                 if (*i == source) {
1531                         return true;
1532                 }
1533
1534                 boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
1535
1536                 if (ps) {
1537                         if (ps->playlist()->uses_source (source)) {
1538                                 return true;
1539                         }
1540                 }
1541         }
1542
1543         return false;
1544 }
1545
1546 framecnt_t
1547 Region::source_length(uint32_t n) const
1548 {
1549         assert (n < _sources.size());
1550         return _sources[n]->length (_position - _start);
1551 }
1552
1553 bool
1554 Region::verify_length (framecnt_t& len)
1555 {
1556         if (source() && (source()->destructive() || source()->length_mutable())) {
1557                 return true;
1558         }
1559
1560         framecnt_t maxlen = 0;
1561
1562         for (uint32_t n = 0; n < _sources.size(); ++n) {
1563                 maxlen = max (maxlen, source_length(n) - _start);
1564         }
1565
1566         len = min (len, maxlen);
1567
1568         return true;
1569 }
1570
1571 bool
1572 Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
1573 {
1574         if (source() && (source()->destructive() || source()->length_mutable())) {
1575                 return true;
1576         }
1577
1578         framecnt_t maxlen = 0;
1579
1580         for (uint32_t n = 0; n < _sources.size(); ++n) {
1581                 maxlen = max (maxlen, source_length(n) - new_start);
1582         }
1583
1584         new_length = min (new_length, maxlen);
1585
1586         return true;
1587 }
1588
1589 bool
1590 Region::verify_start (framepos_t pos)
1591 {
1592         if (source() && (source()->destructive() || source()->length_mutable())) {
1593                 return true;
1594         }
1595
1596         for (uint32_t n = 0; n < _sources.size(); ++n) {
1597                 if (pos > source_length(n) - _length) {
1598                         return false;
1599                 }
1600         }
1601         return true;
1602 }
1603
1604 bool
1605 Region::verify_start_mutable (framepos_t& new_start)
1606 {
1607         if (source() && (source()->destructive() || source()->length_mutable())) {
1608                 return true;
1609         }
1610
1611         for (uint32_t n = 0; n < _sources.size(); ++n) {
1612                 if (new_start > source_length(n) - _length) {
1613                         new_start = source_length(n) - _length;
1614                 }
1615         }
1616         return true;
1617 }
1618
1619 boost::shared_ptr<Region>
1620 Region::get_parent() const
1621 {
1622         boost::shared_ptr<Playlist> pl (playlist());
1623
1624         if (pl) {
1625                 boost::shared_ptr<Region> r;
1626                 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1627
1628                 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1629                         return boost::static_pointer_cast<Region> (r);
1630                 }
1631         }
1632
1633         return boost::shared_ptr<Region>();
1634 }
1635
1636 int
1637 Region::apply (Filter& filter, Progress* progress)
1638 {
1639         return filter.run (shared_from_this(), progress);
1640 }
1641
1642
1643 void
1644 Region::maybe_invalidate_transients ()
1645 {
1646         bool changed = !_onsets.empty();
1647         _onsets.clear ();
1648
1649         if (_valid_transients || changed) {
1650                 send_change (PropertyChange (Properties::valid_transients));
1651                 return;
1652         }
1653 }
1654
1655 void
1656 Region::transients (AnalysisFeatureList& afl)
1657 {
1658         int cnt = afl.empty() ? 0 : 1;
1659
1660         Region::merge_features (afl, _onsets, _position);
1661         Region::merge_features (afl, _user_transients, _position + _transient_user_start - _start);
1662         if (!_onsets.empty ()) {
1663                 ++cnt;
1664         }
1665         if (!_user_transients.empty ()) {
1666                 ++cnt;
1667         }
1668         if (cnt > 1 ) {
1669                 afl.sort ();
1670                 // remove exact duplicates
1671                 TransientDetector::cleanup_transients (afl, _session.frame_rate(), 0);
1672         }
1673 }
1674
1675 bool
1676 Region::has_transients () const
1677 {
1678         if (!_user_transients.empty ()) {
1679                 assert (_valid_transients);
1680                 return true;
1681         }
1682         if (!_onsets.empty ()) {
1683                 return true;
1684         }
1685         return false;
1686 }
1687
1688 void
1689 Region::merge_features (AnalysisFeatureList& result, const AnalysisFeatureList& src, const frameoffset_t off) const
1690 {
1691         for (AnalysisFeatureList::const_iterator x = src.begin(); x != src.end(); ++x) {
1692                 const frameoffset_t p = (*x) + off;
1693                 if (p < first_frame() || p > last_frame()) {
1694                         continue;
1695                 }
1696                 result.push_back (p);
1697         }
1698 }
1699
1700 void
1701 Region::drop_sources ()
1702 {
1703         for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
1704                 (*i)->dec_use_count ();
1705         }
1706
1707         _sources.clear ();
1708
1709         for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
1710                 (*i)->dec_use_count ();
1711         }
1712
1713         _master_sources.clear ();
1714 }
1715
1716 void
1717 Region::use_sources (SourceList const & s)
1718 {
1719         set<boost::shared_ptr<Source> > unique_srcs;
1720
1721         for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1722
1723                 _sources.push_back (*i);
1724                 (*i)->inc_use_count ();
1725                 _master_sources.push_back (*i);
1726                 (*i)->inc_use_count ();
1727
1728                 /* connect only once to DropReferences, even if sources are replicated
1729                  */
1730
1731                 if (unique_srcs.find (*i) == unique_srcs.end ()) {
1732                         unique_srcs.insert (*i);
1733                         (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1734                 }
1735         }
1736 }
1737
1738 Trimmable::CanTrim
1739 Region::can_trim () const
1740 {
1741         CanTrim ct = CanTrim (0);
1742
1743         if (locked()) {
1744                 return ct;
1745         }
1746
1747         /* if not locked, we can always move the front later, and the end earlier
1748          */
1749
1750         ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
1751
1752         if (start() != 0 || can_trim_start_before_source_start ()) {
1753                 ct = CanTrim (ct | FrontTrimEarlier);
1754         }
1755
1756         if (!_sources.empty()) {
1757                 if ((start() + length()) < _sources.front()->length (0)) {
1758                         ct = CanTrim (ct | EndTrimLater);
1759                 }
1760         }
1761
1762         return ct;
1763 }
1764
1765 uint32_t
1766 Region::max_source_level () const
1767 {
1768         uint32_t lvl = 0;
1769
1770         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1771                 lvl = max (lvl, (*i)->level());
1772         }
1773
1774         return lvl;
1775 }
1776
1777 bool
1778 Region::is_compound () const
1779 {
1780         return max_source_level() > 0;
1781 }
1782
1783 void
1784 Region::post_set (const PropertyChange& pc)
1785 {
1786         if (pc.contains (Properties::position)) {
1787                 recompute_position_from_lock_style ();
1788         }
1789 }
1790
1791 void
1792 Region::set_start_internal (framecnt_t s)
1793 {
1794         _start = s;
1795 }
1796
1797 framepos_t
1798 Region::earliest_possible_position () const
1799 {
1800         if (_start > _position) {
1801                 return 0;
1802         } else {
1803                 return _position - _start;
1804         }
1805 }
1806
1807 framecnt_t
1808 Region::latest_possible_frame () const
1809 {
1810         framecnt_t minlen = max_framecnt;
1811
1812         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1813                 /* non-audio regions have a length that may vary based on their
1814                  * position, so we have to pass it in the call.
1815                  */
1816                 minlen = min (minlen, (*i)->length (_position));
1817         }
1818
1819         /* the latest possible last frame is determined by the current
1820          * position, plus the shortest source extent past _start.
1821          */
1822
1823         return _position + (minlen - _start) - 1;
1824 }
1825