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