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