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