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