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