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