new file
[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
27 #include <glibmm/thread.h>
28 #include "pbd/xml++.h"
29 #include "pbd/stacktrace.h"
30 #include "pbd/enumwriter.h"
31
32 #include "ardour/debug.h"
33 #include "ardour/region.h"
34 #include "ardour/playlist.h"
35 #include "ardour/session.h"
36 #include "ardour/source.h"
37 #include "ardour/tempo.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/filter.h"
40 #include "ardour/profile.h"
41 #include "ardour/utils.h"
42
43 #include "i18n.h"
44
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48
49 Change Region::FadeChanged       = PBD::new_change ();
50 Change Region::SyncOffsetChanged = PBD::new_change ();
51 Change Region::MuteChanged       = PBD::new_change ();
52 Change Region::OpacityChanged    = PBD::new_change ();
53 Change Region::LockChanged       = PBD::new_change ();
54 Change Region::LayerChanged      = PBD::new_change ();
55 Change Region::HiddenChanged     = PBD::new_change ();
56
57 PBD::Signal1<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
58
59 void
60 Region::register_states ()
61 {
62         _xml_node_name = X_("Region");
63         add_state (_flags);
64         add_state (_start);
65         add_state (_length);
66         add_state (_position);
67         add_state (_sync_position);
68         add_state (_layer);
69         add_state (_ancestral_start);
70         add_state (_ancestral_length);
71         add_state (_stretch);
72         add_state (_shift);
73 }
74
75 /* derived-from-derived constructor (no sources in constructor) */
76 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
77         : SessionObject(s, name)
78         , _type(type)
79         , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
80         , _start (X_("start"), StartChanged, start)
81         , _length (X_("length"), LengthChanged, length)
82         , _position (X_("position"), PositionChanged, 0)
83         , _last_position (0)
84         , _positional_lock_style(AudioTime)
85         , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
86         , _layer (X_("layer"), LayerChanged, layer)
87         , _first_edit(EditChangesNothing)
88         , _frozen(0)
89         , _ancestral_start (X_("ancestral-start"), Change (0), 0)
90         , _ancestral_length (X_("ancestral-length"), Change (0), 0)
91         , _stretch (X_("stretch"), Change (0), 1.0)
92         , _shift (X_("shift"), Change (0), 1.0)
93         , _read_data_count(0)
94         , _pending_changed(Change (0))
95         , _last_layer_op(0)
96         , _pending_explicit_relayer (false)
97 {
98         register_states ();
99         
100         /* no sources at this point */
101 }
102
103 /** Basic Region constructor (single source) */
104 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
105         : SessionObject(src->session(), name)
106         , _type(type)
107         , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
108         , _start (X_("start"), StartChanged, start)
109         , _length (X_("length"), LengthChanged, length)
110         , _position (X_("position"), PositionChanged, 0)
111         , _last_position(0)
112         , _positional_lock_style(AudioTime)
113         , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
114         , _layer (X_("layer"), LayerChanged, layer)
115         , _first_edit(EditChangesNothing)
116         , _frozen(0)
117         , _ancestral_start (X_("ancestral-start"), Change (0), 0)
118         , _ancestral_length (X_("ancestral-length"), Change (0), 0)
119         , _stretch (X_("stretch"), Change (0), 1.0)
120         , _shift (X_("shift"), Change (0), 1.0)
121         , _valid_transients(false)
122         , _read_data_count(0)
123         , _pending_changed(Change (0))
124         , _last_layer_op(0)
125         , _pending_explicit_relayer (false)
126 {
127         register_states ();
128
129         _sources.push_back (src);
130         _master_sources.push_back (src);
131
132         src->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
133
134         assert(_sources.size() > 0);
135         _positional_lock_style = AudioTime;
136 }
137
138 /** Basic Region constructor (many sources) */
139 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
140         : SessionObject(srcs.front()->session(), name)
141         , _type(type)
142         , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
143         , _start (X_("start"), StartChanged, start)
144         , _length (X_("length"), LengthChanged, length)
145         , _position (X_("position"), PositionChanged, 0)
146         , _last_position(0)
147         , _positional_lock_style(AudioTime)
148         , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
149         , _layer (X_("layer"), LayerChanged, layer)
150         , _first_edit(EditChangesNothing)
151         , _frozen(0)
152         , _ancestral_start (X_("ancestral-start"), Change (0), 0)
153         , _ancestral_length (X_("ancestral-length"), Change (0), 0)
154         , _stretch (X_("stretch"), Change (0), 1.0)
155         , _shift (X_("shift"), Change (0), 1.0)
156         , _read_data_count(0)
157         , _pending_changed(Change (0))
158         , _last_layer_op(0)
159         , _pending_explicit_relayer (false)
160 {
161         register_states ();
162
163         use_sources (srcs);
164         assert(_sources.size() > 0);
165 }
166
167 /** Create a new Region from part of an existing one */
168 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
169         : SessionObject(other->session(), name)
170         , _type (other->data_type())
171         , _flags (X_("flags"), FlagsChanged, Flag (flags | DoNotSendPropertyChanges))
172         , _start (X_("start"), StartChanged, 0)
173         , _length (X_("length"), LengthChanged, 0)
174         , _position (X_("position"), PositionChanged, 0)
175         , _sync_position (X_("sync-position"), SyncOffsetChanged, 0)
176         , _layer (X_("layer"), LayerChanged, 0)
177         , _ancestral_start (X_("ancestral-start"), Change (0), 0)
178         , _ancestral_length (X_("ancestral-length"), Change (0), 0)
179         , _stretch (X_("stretch"), Change (0), 1.0)
180         , _shift (X_("shift"), Change (0), 1.0)
181         , _pending_explicit_relayer (false)
182
183 {
184         register_states ();
185
186         _start = other->_start + offset;
187         copy_stuff (other, offset, length, name, layer, flags);
188
189         /* if the other region had a distinct sync point
190            set, then continue to use it as best we can.
191            otherwise, reset sync point back to start.
192         */
193
194         if (other->flags() & SyncMarked) {
195                 if (other->_sync_position < _start) {
196                         _flags = Flag (_flags & ~SyncMarked);
197                         _sync_position = _start;
198                 } else {
199                         _sync_position = other->_sync_position;
200                 }
201         } else {
202                 _flags = Flag (_flags & ~SyncMarked);
203                 _sync_position = _start;
204         }
205
206         if (Profile->get_sae()) {
207                 /* reset sync point to start if its ended up
208                    outside region bounds.
209                 */
210
211                 if (_sync_position < _start || _sync_position >= _start + _length) {
212                         _flags = Flag (_flags & ~SyncMarked);
213                         _sync_position = _start;
214                 }
215         }
216 }
217
218 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
219         : SessionObject(other->session(), name)
220         , _type (other->data_type())
221         , _flags (X_("flags"), FlagsChanged, Flag (flags|DoNotSendPropertyChanges))
222         , _start (X_("start"), StartChanged, 0)
223         , _length (X_("length"), LengthChanged, 0)
224         , _position (X_("position"), PositionChanged, 0)
225         , _sync_position (X_("sync-position"), SyncOffsetChanged, 0)
226         , _layer (X_("layer"), LayerChanged, 0)
227         , _ancestral_start (X_("ancestral-start"), Change (0), 0)
228         , _ancestral_length (X_("ancestral-length"), Change (0), 0)
229         , _stretch (X_("stretch"), Change (0), 1.0)
230         , _shift (X_("shift"), Change (0), 1.0)
231         , _pending_explicit_relayer (false)
232 {
233         register_states ();
234
235         /* create a new Region exactly like another but starting at 0 in its sources */
236
237         _start = 0;
238         copy_stuff (other, 0, length, name, layer, flags);
239
240         _flags = Flag (_flags | DoNotSendPropertyChanges);
241
242         /* sync pos is relative to start of file. our start-in-file is now zero,
243            so set our sync position to whatever the the difference between
244            _start and _sync_pos was in the other region.
245
246            result is that our new sync pos points to the same point in our source(s)
247            as the sync in the other region did in its source(s).
248
249            since we start at zero in our source(s), it is not possible to use a sync point that
250            is before the start. reset it to _start if that was true in the other region.
251         */
252
253         if (other->flags() & SyncMarked) {
254                 if (other->_start < other->_sync_position) {
255                         /* sync pos was after the start point of the other region */
256                         _sync_position = other->_sync_position - other->_start;
257                 } else {
258                         /* sync pos was before the start point of the other region. not possible here. */
259                         _flags = Flag (_flags & ~SyncMarked);
260                         _sync_position = _start;
261                 }
262         } else {
263                 _flags = Flag (_flags & ~SyncMarked);
264                 _sync_position = _start;
265         }
266
267         if (Profile->get_sae()) {
268                 /* reset sync point to start if its ended up
269                    outside region bounds.
270                 */
271
272                 if (_sync_position < _start || _sync_position >= _start + _length) {
273                         _flags = Flag (_flags & ~SyncMarked);
274                         _sync_position = _start;
275                 }
276         }
277
278         /* reset a couple of things that copy_stuff() gets wrong in this particular case */
279
280         _positional_lock_style = other->_positional_lock_style;
281         _first_edit = other->_first_edit;
282 }
283
284 /** Pure copy constructor */
285 Region::Region (boost::shared_ptr<const Region> other)
286         : SessionObject(other->session(), other->name())
287         , _type(other->data_type())
288         , _flags (other->_flags)
289         , _start(other->_start)
290         , _length(other->_length)
291         , _position(other->_position)
292         , _last_position(other->_last_position)
293         , _positional_lock_style(other->_positional_lock_style)
294         , _sync_position(other->_sync_position)
295         , _layer(other->_layer)
296         , _first_edit(EditChangesID)
297         , _frozen(0)
298         , _ancestral_start (other->_ancestral_start)
299         , _ancestral_length (other->_ancestral_length)
300         , _stretch (other->_stretch)
301         , _shift (other->_shift)
302         , _valid_transients(false)
303         , _read_data_count(0)
304         , _pending_changed(Change(0))
305         , _last_layer_op(other->_last_layer_op)
306         , _pending_explicit_relayer (false)
307 {
308         register_states ();
309
310         _flags = Flag (_flags & ~ (Locked | PositionLocked));
311         _flags = Flag (_flags | DoNotSendPropertyChanges);
312
313         other->_first_edit = EditChangesName;
314
315         if (other->_extra_xml) {
316                 _extra_xml = new XMLNode (*other->_extra_xml);
317         } else {
318                 _extra_xml = 0;
319         }
320
321         use_sources (other->_sources);
322         assert(_sources.size() > 0);
323 }
324
325 Region::Region (const SourceList& srcs, const XMLNode& node)
326         : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
327         , _type(DataType::NIL) // to be loaded from XML
328         , _flags (X_("flags"), FlagsChanged, Flag (DoNotSendPropertyChanges))
329         , _start (X_("start"), StartChanged, 0)
330         , _length (X_("length"), LengthChanged, 0)
331         , _position (X_("position"), PositionChanged, 0)
332         , _last_position(0)
333         , _positional_lock_style(AudioTime)
334         , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
335         , _layer (X_("layer"), LayerChanged, 0)
336         , _first_edit(EditChangesNothing)
337         , _frozen(0)
338         , _ancestral_start (X_("ancestral-start"), Change (0), 0)
339         , _ancestral_length (X_("ancestral-length"), Change (0), 0)
340         , _stretch (X_("stretch"), Change (0), 1.0)
341         , _shift (X_("shift"), Change (0), 1.0)
342         , _read_data_count(0)
343         , _pending_changed(Change(0))
344         , _last_layer_op(0)
345         , _pending_explicit_relayer (false)
346 {
347         register_states ();
348
349         use_sources (srcs);
350
351         if (set_state (node, Stateful::loading_state_version)) {
352                 throw failed_constructor();
353         }
354
355         assert(_type != DataType::NIL);
356         assert(_sources.size() > 0);
357 }
358
359 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
360         : SessionObject(src->session(), X_("error: XML did not reset this"))
361         , _type(DataType::NIL)
362         , _flags (X_("flags"), FlagsChanged, Flag (DoNotSendPropertyChanges))
363         , _start (X_("start"), StartChanged, 0)
364         , _length (X_("length"), LengthChanged, 0)
365         , _position (X_("position"), PositionChanged, 0)
366         , _last_position(0)
367         , _positional_lock_style(AudioTime)
368         , _sync_position (X_("sync-position"), SyncOffsetChanged, _start)
369         , _layer (X_("layer"), LayerChanged, 0)
370         , _first_edit(EditChangesNothing)
371         , _frozen(0)
372         , _ancestral_start (X_("ancestral-start"), Change (0), 0)
373         , _ancestral_length (X_("ancestral-length"), Change (0), 0)
374         , _stretch (X_("stretch"), Change (0), 1.0)
375         , _shift (X_("shift"), Change (0), 1.0)
376         , _read_data_count(0)
377         , _pending_changed(Change(0))
378         , _last_layer_op(0)
379         , _pending_explicit_relayer (false)
380 {
381         register_states ();
382
383         _sources.push_back (src);
384
385         if (set_state (node, Stateful::loading_state_version)) {
386                 throw failed_constructor();
387         }
388
389         assert(_type != DataType::NIL);
390         assert(_sources.size() > 0);
391 }
392
393 Region::~Region ()
394 {
395         DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
396 }
397
398 void
399 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
400 {
401         _frozen = 0;
402         _pending_changed = Change (0);
403         _read_data_count = 0;
404         _valid_transients = false;
405
406         _length = length;
407         _last_length = length;
408         _sync_position = other->_sync_position;
409         _ancestral_start = other->_ancestral_start;
410         _ancestral_length = other->_ancestral_length;
411         _stretch = other->_stretch;
412         _shift = other->_shift;
413         _name = name;
414         _last_position = 0;
415         _position = 0;
416         _layer = layer;
417         _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
418         _first_edit = EditChangesNothing;
419         _last_layer_op = 0;
420         _positional_lock_style = AudioTime;
421
422         use_sources (other->_sources);
423 }
424
425 void
426 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
427 {
428         _playlist = wpl.lock();
429 }
430
431 bool
432 Region::set_name (const std::string& str)
433 {
434         if (_name != str) {
435                 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
436                 assert(_name == str);
437                 send_change (ARDOUR::NameChanged);
438         }
439
440         return true;
441 }
442
443 void
444 Region::set_length (nframes_t len, void */*src*/)
445 {
446         //cerr << "Region::set_length() len = " << len << endl;
447         if (_flags & Locked) {
448                 return;
449         }
450
451         if (_length != len && len != 0) {
452
453                 /* check that the current _position wouldn't make the new
454                    length impossible.
455                 */
456
457                 if (max_frames - len < _position) {
458                         return;
459                 }
460
461                 if (!verify_length (len)) {
462                         return;
463                 }
464
465
466                 _last_length = _length;
467                 _length = len;
468
469                 _flags = Region::Flag (_flags & ~WholeFile);
470
471                 first_edit ();
472                 maybe_uncopy ();
473                 invalidate_transients ();
474
475                 if (!_frozen) {
476                         recompute_at_end ();
477                 }
478
479                 send_change (LengthChanged);
480         }
481 }
482
483 void
484 Region::maybe_uncopy ()
485 {
486 }
487
488 void
489 Region::first_edit ()
490 {
491         boost::shared_ptr<Playlist> pl (playlist());
492
493         if (_first_edit != EditChangesNothing && pl) {
494
495                 _name = _session.new_region_name (_name);
496                 _first_edit = EditChangesNothing;
497
498                 send_change (ARDOUR::NameChanged);
499                 RegionFactory::CheckNewRegion (shared_from_this());
500         }
501 }
502
503 bool
504 Region::at_natural_position () const
505 {
506         boost::shared_ptr<Playlist> pl (playlist());
507
508         if (!pl) {
509                 return false;
510         }
511
512         boost::shared_ptr<Region> whole_file_region = get_parent();
513
514         if (whole_file_region) {
515                 if (_position == whole_file_region->position() + _start) {
516                         return true;
517                 }
518         }
519
520         return false;
521 }
522
523 void
524 Region::move_to_natural_position (void *src)
525 {
526         boost::shared_ptr<Playlist> pl (playlist());
527
528         if (!pl) {
529                 return;
530         }
531
532         boost::shared_ptr<Region> whole_file_region = get_parent();
533
534         if (whole_file_region) {
535                 set_position (whole_file_region->position() + _start, src);
536         }
537 }
538
539 void
540 Region::special_set_position (nframes_t pos)
541 {
542         /* this is used when creating a whole file region as
543            a way to store its "natural" or "captured" position.
544         */
545
546         _position = _position;
547         _position = pos;
548 }
549
550 void
551 Region::set_position_lock_style (PositionLockStyle ps)
552 {
553         boost::shared_ptr<Playlist> pl (playlist());
554
555         if (!pl) {
556                 return;
557         }
558
559         _positional_lock_style = ps;
560
561         if (_positional_lock_style == MusicTime) {
562                 _session.tempo_map().bbt_time (_position, _bbt_time);
563         }
564
565 }
566
567 void
568 Region::update_position_after_tempo_map_change ()
569 {
570         boost::shared_ptr<Playlist> pl (playlist());
571
572         if (!pl || _positional_lock_style != MusicTime) {
573                 return;
574         }
575
576         TempoMap& map (_session.tempo_map());
577         nframes_t pos = map.frame_time (_bbt_time);
578         set_position_internal (pos, false);
579 }
580
581 void
582 Region::set_position (nframes_t pos, void* /*src*/)
583 {
584         if (!can_move()) {
585                 return;
586         }
587
588         set_position_internal (pos, true);
589 }
590
591 void
592 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
593 {
594         if (_position != pos) {
595                 _last_position = _position;
596                 _position = pos;
597
598                 /* check that the new _position wouldn't make the current
599                    length impossible - if so, change the length.
600
601                    XXX is this the right thing to do?
602                 */
603
604                 if (max_frames - _length < _position) {
605                         _last_length = _length;
606                         _length = max_frames - _position;
607                 }
608
609                 if (allow_bbt_recompute) {
610                         recompute_position_from_lock_style ();
611                 }
612
613                 invalidate_transients ();
614         }
615
616         /* do this even if the position is the same. this helps out
617            a GUI that has moved its representation already.
618         */
619
620         send_change (PositionChanged);
621 }
622
623 void
624 Region::set_position_on_top (nframes_t pos, void* /*src*/)
625 {
626         if (_flags & Locked) {
627                 return;
628         }
629
630         if (_position != pos) {
631                 _last_position = _position;
632                 _position = pos;
633         }
634
635         boost::shared_ptr<Playlist> pl (playlist());
636
637         if (pl) {
638                 pl->raise_region_to_top (shared_from_this ());
639         }
640
641         /* do this even if the position is the same. this helps out
642            a GUI that has moved its representation already.
643         */
644
645         send_change (PositionChanged);
646 }
647
648 void
649 Region::recompute_position_from_lock_style ()
650 {
651         if (_positional_lock_style == MusicTime) {
652                 _session.tempo_map().bbt_time (_position, _bbt_time);
653         }
654 }
655
656 void
657 Region::nudge_position (nframes64_t n, void* /*src*/)
658 {
659         if (_flags & Locked) {
660                 return;
661         }
662
663         if (n == 0) {
664                 return;
665         }
666
667         _last_position = _position;
668
669         if (n > 0) {
670                 if (_position > max_frames - n) {
671                         _position = max_frames;
672                 } else {
673                         _position += n;
674                 }
675         } else {
676                 if (_position < (nframes_t) -n) {
677                         _position = 0;
678                 } else {
679                         _position += n;
680                 }
681         }
682
683         send_change (PositionChanged);
684 }
685
686 void
687 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
688 {
689         _ancestral_length = l;
690         _ancestral_start = s;
691         _stretch = st;
692         _shift = sh;
693 }
694
695 void
696 Region::set_start (nframes_t pos, void* /*src*/)
697 {
698         if (_flags & (Locked|PositionLocked)) {
699                 return;
700         }
701         /* This just sets the start, nothing else. It effectively shifts
702            the contents of the Region within the overall extent of the Source,
703            without changing the Region's position or length
704         */
705
706         if (_start != pos) {
707
708                 if (!verify_start (pos)) {
709                         return;
710                 }
711
712                 _start = pos;
713                 _flags = Region::Flag (_flags & ~WholeFile);
714                 first_edit ();
715                 invalidate_transients ();
716
717                 send_change (StartChanged);
718         }
719 }
720
721 void
722 Region::trim_start (nframes_t new_position, void */*src*/)
723 {
724         if (_flags & (Locked|PositionLocked)) {
725                 return;
726         }
727         nframes_t new_start;
728         int32_t start_shift;
729
730         if (new_position > _position) {
731                 start_shift = new_position - _position;
732         } else {
733                 start_shift = -(_position - new_position);
734         }
735
736         if (start_shift > 0) {
737
738                 if (_start > max_frames - start_shift) {
739                         new_start = max_frames;
740                 } else {
741                         new_start = _start + start_shift;
742                 }
743
744                 if (!verify_start (new_start)) {
745                         return;
746                 }
747
748         } else if (start_shift < 0) {
749
750                 if (_start < (nframes_t) -start_shift) {
751                         new_start = 0;
752                 } else {
753                         new_start = _start + start_shift;
754                 }
755         } else {
756                 return;
757         }
758
759         if (new_start == _start) {
760                 return;
761         }
762
763         _start = new_start;
764         _flags = Region::Flag (_flags & ~WholeFile);
765         first_edit ();
766
767         send_change (StartChanged);
768 }
769
770 void
771 Region::trim_front (nframes_t new_position, void *src)
772 {
773         if (_flags & Locked) {
774                 return;
775         }
776
777         nframes_t end = last_frame();
778         nframes_t source_zero;
779
780         if (_position > _start) {
781                 source_zero = _position - _start;
782         } else {
783                 source_zero = 0; // its actually negative, but this will work for us
784         }
785
786         if (new_position < end) { /* can't trim it zero or negative length */
787
788                 nframes_t newlen;
789
790                 /* can't trim it back passed where source position zero is located */
791
792                 new_position = max (new_position, source_zero);
793
794
795                 if (new_position > _position) {
796                         newlen = _length - (new_position - _position);
797                 } else {
798                         newlen = _length + (_position - new_position);
799                 }
800
801                 trim_to_internal (new_position, newlen, src);
802                 if (!_frozen) {
803                         recompute_at_start ();
804                 }
805         }
806 }
807
808 /** @param new_endpoint New region end point, such that, for example,
809  *  a region at 0 of length 10 has an endpoint of 9.
810  */
811
812 void
813 Region::trim_end (nframes_t new_endpoint, void */*src*/)
814 {
815         if (_flags & Locked) {
816                 return;
817         }
818
819         if (new_endpoint > _position) {
820                 trim_to_internal (_position, new_endpoint - _position + 1, this);
821                 if (!_frozen) {
822                         recompute_at_end ();
823                 }
824         }
825 }
826
827 void
828 Region::trim_to (nframes_t position, nframes_t length, void *src)
829 {
830         if (_flags & Locked) {
831                 return;
832         }
833
834         trim_to_internal (position, length, src);
835
836         if (!_frozen) {
837                 recompute_at_start ();
838                 recompute_at_end ();
839         }
840 }
841
842 void
843 Region::trim_to_internal (nframes_t position, nframes_t length, void */*src*/)
844 {
845         int32_t start_shift;
846         nframes_t new_start;
847
848         if (_flags & Locked) {
849                 return;
850         }
851
852         if (position > _position) {
853                 start_shift = position - _position;
854         } else {
855                 start_shift = -(_position - position);
856         }
857
858         if (start_shift > 0) {
859
860                 if (_start > max_frames - start_shift) {
861                         new_start = max_frames;
862                 } else {
863                         new_start = _start + start_shift;
864                 }
865
866
867         } else if (start_shift < 0) {
868
869                 if (_start < (nframes_t) -start_shift) {
870                         new_start = 0;
871                 } else {
872                         new_start = _start + start_shift;
873                 }
874         } else {
875                 new_start = _start;
876         }
877
878         if (!verify_start_and_length (new_start, length)) {
879                 return;
880         }
881
882         Change what_changed = Change (0);
883
884         if (_start != new_start) {
885                 _start = new_start;
886                 what_changed = Change (what_changed|StartChanged);
887         }
888         if (_length != length) {
889                 if (!_frozen) {
890                         _last_length = _length;
891                 }
892                 _length = length;
893                 what_changed = Change (what_changed|LengthChanged);
894         }
895         if (_position != position) {
896                 if (!_frozen) {
897                         _last_position = _position;
898                 }
899                 _position = position;
900                 what_changed = Change (what_changed|PositionChanged);
901         }
902
903         _flags = Region::Flag (_flags & ~WholeFile);
904
905         if (what_changed & (StartChanged|LengthChanged)) {
906                 first_edit ();
907         }
908
909         if (what_changed) {
910                 send_change (what_changed);
911         }
912 }
913
914 void
915 Region::set_hidden (bool yn)
916 {
917         if (hidden() != yn) {
918
919                 if (yn) {
920                         _flags = Flag (_flags|Hidden);
921                 } else {
922                         _flags = Flag (_flags & ~Hidden);
923                 }
924
925                 send_change (HiddenChanged);
926         }
927 }
928
929 void
930 Region::set_muted (bool yn)
931 {
932         if (muted() != yn) {
933
934                 if (yn) {
935                         _flags = Flag (_flags|Muted);
936                 } else {
937                         _flags = Flag (_flags & ~Muted);
938                 }
939
940                 send_change (MuteChanged);
941         }
942 }
943
944 void
945 Region::set_opaque (bool yn)
946 {
947         if (opaque() != yn) {
948                 if (yn) {
949                         _flags = Flag (_flags|Opaque);
950                 } else {
951                         _flags = Flag (_flags & ~Opaque);
952                 }
953                 send_change (OpacityChanged);
954         }
955 }
956
957 void
958 Region::set_locked (bool yn)
959 {
960         if (locked() != yn) {
961                 if (yn) {
962                         _flags = Flag (_flags|Locked);
963                 } else {
964                         _flags = Flag (_flags & ~Locked);
965                 }
966                 send_change (LockChanged);
967         }
968 }
969
970 void
971 Region::set_position_locked (bool yn)
972 {
973         if (position_locked() != yn) {
974                 if (yn) {
975                         _flags = Flag (_flags|PositionLocked);
976                 } else {
977                         _flags = Flag (_flags & ~PositionLocked);
978                 }
979                 send_change (LockChanged);
980         }
981 }
982
983 void
984 Region::set_sync_position (nframes_t absolute_pos)
985 {
986         nframes_t const file_pos = _start + (absolute_pos - _position);
987
988         if (file_pos != _sync_position) {
989
990                 _sync_position = file_pos;
991                 _flags = Flag (_flags|SyncMarked);
992
993                 if (!_frozen) {
994                         maybe_uncopy ();
995                 }
996                 send_change (SyncOffsetChanged);
997         }
998 }
999
1000 void
1001 Region::clear_sync_position ()
1002 {
1003         if (_flags & SyncMarked) {
1004                 _flags = Flag (_flags & ~SyncMarked);
1005
1006                 if (!_frozen) {
1007                         maybe_uncopy ();
1008                 }
1009                 send_change (SyncOffsetChanged);
1010         }
1011 }
1012
1013 nframes_t
1014 Region::sync_offset (int& dir) const
1015 {
1016         /* returns the sync point relative the first frame of the region */
1017
1018         if (_flags & SyncMarked) {
1019                 if (_sync_position > _start) {
1020                         dir = 1;
1021                         return _sync_position - _start;
1022                 } else {
1023                         dir = -1;
1024                         return _start - _sync_position;
1025                 }
1026         } else {
1027                 dir = 0;
1028                 return 0;
1029         }
1030 }
1031
1032 nframes_t
1033 Region::adjust_to_sync (nframes_t pos) const
1034 {
1035         int sync_dir;
1036         nframes_t offset = sync_offset (sync_dir);
1037
1038         // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1039
1040         if (sync_dir > 0) {
1041                 if (pos > offset) {
1042                         pos -= offset;
1043                 } else {
1044                         pos = 0;
1045                 }
1046         } else {
1047                 if (max_frames - pos > offset) {
1048                         pos += offset;
1049                 }
1050         }
1051
1052         return pos;
1053 }
1054
1055 nframes_t
1056 Region::sync_position() const
1057 {
1058         if (_flags & SyncMarked) {
1059                 return _sync_position;
1060         } else {
1061                 return _start;
1062         }
1063 }
1064
1065 void
1066 Region::raise ()
1067 {
1068         boost::shared_ptr<Playlist> pl (playlist());
1069         if (pl) {
1070                 pl->raise_region (shared_from_this ());
1071         }
1072 }
1073
1074 void
1075 Region::lower ()
1076 {
1077         boost::shared_ptr<Playlist> pl (playlist());
1078         if (pl) {
1079                 pl->lower_region (shared_from_this ());
1080         }
1081 }
1082
1083
1084 void
1085 Region::raise_to_top ()
1086 {
1087         boost::shared_ptr<Playlist> pl (playlist());
1088         if (pl) {
1089                 pl->raise_region_to_top (shared_from_this());
1090         }
1091 }
1092
1093 void
1094 Region::lower_to_bottom ()
1095 {
1096         boost::shared_ptr<Playlist> pl (playlist());
1097         if (pl) {
1098                 pl->lower_region_to_bottom (shared_from_this());
1099         }
1100 }
1101
1102 void
1103 Region::set_layer (layer_t l)
1104 {
1105         if (_layer != l) {
1106                 _layer = l;
1107
1108                 send_change (LayerChanged);
1109         }
1110 }
1111
1112 XMLNode&
1113 Region::state (bool /*full_state*/)
1114 {
1115         XMLNode *node = new XMLNode ("Region");
1116         char buf[64];
1117         const char* fe = NULL;
1118
1119         add_states (*node);
1120
1121         _id.print (buf, sizeof (buf));
1122         node->add_property ("id", buf);
1123         node->add_property ("type", _type.to_string());
1124
1125         switch (_first_edit) {
1126         case EditChangesNothing:
1127                 fe = X_("nothing");
1128                 break;
1129         case EditChangesName:
1130                 fe = X_("name");
1131                 break;
1132         case EditChangesID:
1133                 fe = X_("id");
1134                 break;
1135         default: /* should be unreachable but makes g++ happy */
1136                 fe = X_("nothing");
1137                 break;
1138         }
1139
1140         node->add_property ("first-edit", fe);
1141
1142         /* note: flags are stored by derived classes */
1143
1144         if (_positional_lock_style != AudioTime) {
1145                 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1146                 stringstream str;
1147                 str << _bbt_time;
1148                 node->add_property ("bbt-position", str.str());
1149         }
1150
1151         return *node;
1152 }
1153
1154 XMLNode&
1155 Region::get_state ()
1156 {
1157         return state (true);
1158 }
1159
1160 int
1161 Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
1162 {
1163         const XMLNodeList& nlist = node.children();
1164         const XMLProperty *prop;
1165
1166         /* this is responsible for setting those aspects of Region state
1167            that are mutable after construction.
1168         */
1169
1170         if ((prop = node.property ("type")) == 0) {
1171                 _type = DataType::AUDIO;
1172         } else {
1173                 _type = DataType(prop->value());
1174         }
1175
1176         if ((prop = node.property ("positional-lock-style")) != 0) {
1177                 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1178
1179                 if (_positional_lock_style == MusicTime) {
1180                         if ((prop = node.property ("bbt-position")) == 0) {
1181                                 /* missing BBT info, revert to audio time locking */
1182                                 _positional_lock_style = AudioTime;
1183                         } else {
1184                                 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1185                                             &_bbt_time.bars,
1186                                             &_bbt_time.beats,
1187                                             &_bbt_time.ticks) != 3) {
1188                                         _positional_lock_style = AudioTime;
1189                                 }
1190                         }
1191                 }
1192
1193         }
1194
1195         /* XXX FIRST EDIT !!! */
1196
1197         /* fix problems with old sessions corrupted by impossible
1198            values for _stretch or _shift
1199         */
1200         if (_stretch == 0.0f) {
1201                 _stretch = 1.0f;
1202         }
1203         
1204         if (_shift == 0.0f) {
1205                 _shift = 1.0f;
1206         }
1207
1208         /* note: derived classes set flags */
1209
1210         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1211
1212                 XMLNode *child;
1213
1214                 child = (*niter);
1215
1216                 if (child->name () == "Extra") {
1217                         delete _extra_xml;
1218                         _extra_xml = new XMLNode (*child);
1219                         break;
1220                 }
1221         }
1222
1223         if (send) {
1224                 cerr << _name << ": final change to be sent: " << hex << what_changed << dec << endl;
1225                 send_change (what_changed);
1226         }
1227
1228         return 0;
1229 }
1230
1231 int
1232 Region::set_state (const XMLNode& node, int version)
1233 {
1234         const XMLProperty *prop;
1235
1236         /* ID is not allowed to change, ever */
1237
1238         if ((prop = node.property ("id"))) {
1239                 _id = prop->value();
1240         }
1241
1242         _first_edit = EditChangesNothing;
1243
1244         uint32_t old_flags = _flags;
1245
1246         Change what_changed = set_state_using_states (node);
1247
1248         /* leave this flag setting in place, no matter what */
1249
1250         if ((old_flags & DoNotSendPropertyChanges)) {
1251                 _flags = Flag (_flags | DoNotSendPropertyChanges);
1252         }
1253
1254         if ((old_flags ^ _flags) & Muted) {
1255                 what_changed = Change (what_changed|MuteChanged);
1256                 cerr << _name << " mute changed\n";
1257         }
1258         if ((old_flags ^ _flags) & Opaque) {
1259                 what_changed = Change (what_changed|OpacityChanged);
1260                 cerr << _name << " opacity changed\n";
1261         }
1262         if ((old_flags ^ _flags) & Locked) {
1263                 what_changed = Change (what_changed|LockChanged);
1264                 cerr << _name << " lock changed\n";
1265         }
1266
1267         set_live_state (node, version, what_changed, true);
1268
1269         return 0;
1270 }
1271
1272 void
1273 Region::freeze ()
1274 {
1275         _frozen++;
1276         _last_length = _length;
1277         _last_position = _position;
1278 }
1279
1280 void
1281 Region::thaw ()
1282 {
1283         Change what_changed = Change (0);
1284
1285         {
1286                 Glib::Mutex::Lock lm (_lock);
1287
1288                 if (_frozen && --_frozen > 0) {
1289                         return;
1290                 }
1291
1292                 if (_pending_changed) {
1293                         what_changed = _pending_changed;
1294                         _pending_changed = Change (0);
1295                 }
1296         }
1297
1298         if (what_changed == Change (0)) {
1299                 return;
1300         }
1301
1302         if (what_changed & LengthChanged) {
1303                 if (what_changed & PositionChanged) {
1304                         recompute_at_start ();
1305                 }
1306                 recompute_at_end ();
1307         }
1308
1309         send_change (what_changed);
1310 }
1311
1312 void
1313 Region::send_change (Change what_changed)
1314 {
1315
1316         {
1317                 Glib::Mutex::Lock lm (_lock);
1318                 if (_frozen) {
1319                         _pending_changed = Change (_pending_changed|what_changed);
1320                         return;
1321                 }
1322         }
1323
1324         cerr << _name << " actually sends " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1325         StateChanged (what_changed);
1326         cerr << _name << " done with " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1327
1328         if (!(_flags & DoNotSendPropertyChanges)) {
1329
1330                 /* Try and send a shared_pointer unless this is part of the constructor.
1331                    If so, do nothing.
1332                 */
1333
1334                 try {
1335                         boost::shared_ptr<Region> rptr = shared_from_this();
1336                         cerr << _name << " actually sends prop change " << hex << what_changed << dec <<  " @ " << get_microseconds() << endl;
1337                         RegionPropertyChanged (rptr);
1338                         cerr << _name << " done with prop change  @ " << get_microseconds() << endl;
1339
1340                 } catch (...) {
1341                         /* no shared_ptr available, relax; */
1342                 }
1343         }
1344
1345 }
1346
1347 void
1348 Region::set_last_layer_op (uint64_t when)
1349 {
1350         _last_layer_op = when;
1351 }
1352
1353 bool
1354 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1355 {
1356         return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1357 }
1358
1359 bool
1360 Region::equivalent (boost::shared_ptr<const Region> other) const
1361 {
1362         return _start == other->_start &&
1363                 _position == other->_position &&
1364                 _length == other->_length;
1365 }
1366
1367 bool
1368 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1369 {
1370         return _start == other->_start &&
1371                 _length == other->_length;
1372 }
1373
1374 bool
1375 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1376 {
1377         return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1378 }
1379
1380 void
1381 Region::source_deleted (boost::weak_ptr<Source>)
1382 {
1383         _sources.clear ();
1384
1385         if (!_session.deletion_in_progress()) {
1386                 /* this is a very special case: at least one of the region's
1387                    sources has bee deleted, so invalidate all references to
1388                    ourselves. Do NOT do this during session deletion, because
1389                    then we run the risk that this will actually result
1390                    in this object being deleted (as refcnt goes to zero)
1391                    while emitting DropReferences.
1392                 */
1393
1394                 drop_references ();
1395         }
1396 }
1397
1398 vector<string>
1399 Region::master_source_names ()
1400 {
1401         SourceList::iterator i;
1402
1403         vector<string> names;
1404         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1405                 names.push_back((*i)->name());
1406         }
1407
1408         return names;
1409 }
1410
1411 void
1412 Region::set_master_sources (const SourceList& srcs)
1413 {
1414         _master_sources = srcs;
1415         assert (_sources.size() == _master_sources.size());
1416 }
1417
1418 bool
1419 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1420 {
1421         if (!other)
1422                 return false;
1423
1424         SourceList::const_iterator i;
1425         SourceList::const_iterator io;
1426
1427         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1428                 if ((*i)->id() != (*io)->id()) {
1429                         return false;
1430                 }
1431         }
1432
1433         for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1434                 if ((*i)->id() != (*io)->id()) {
1435                         return false;
1436                 }
1437         }
1438
1439         return true;
1440 }
1441
1442 bool
1443 Region::uses_source (boost::shared_ptr<const Source> source) const
1444 {
1445         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1446                 if (*i == source) {
1447                         return true;
1448                 }
1449         }
1450         return false;
1451 }
1452
1453 sframes_t
1454 Region::source_length(uint32_t n) const
1455 {
1456         return _sources[n]->length(_position - _start);
1457 }
1458
1459 bool
1460 Region::verify_length (nframes_t len)
1461 {
1462         if (source() && (source()->destructive() || source()->length_mutable())) {
1463                 return true;
1464         }
1465
1466         nframes_t maxlen = 0;
1467
1468         for (uint32_t n=0; n < _sources.size(); ++n) {
1469                 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1470         }
1471
1472         len = min (len, maxlen);
1473
1474         return true;
1475 }
1476
1477 bool
1478 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1479 {
1480         if (source() && (source()->destructive() || source()->length_mutable())) {
1481                 return true;
1482         }
1483
1484         nframes_t maxlen = 0;
1485
1486         for (uint32_t n=0; n < _sources.size(); ++n) {
1487                 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1488         }
1489
1490         new_length = min (new_length, maxlen);
1491
1492         return true;
1493 }
1494
1495 bool
1496 Region::verify_start (nframes_t pos)
1497 {
1498         if (source() && (source()->destructive() || source()->length_mutable())) {
1499                 return true;
1500         }
1501
1502         for (uint32_t n=0; n < _sources.size(); ++n) {
1503                 if (pos > source_length(n) - _length) {
1504                         return false;
1505                 }
1506         }
1507         return true;
1508 }
1509
1510 bool
1511 Region::verify_start_mutable (nframes_t& new_start)
1512 {
1513         if (source() && (source()->destructive() || source()->length_mutable())) {
1514                 return true;
1515         }
1516
1517         for (uint32_t n=0; n < _sources.size(); ++n) {
1518                 if (new_start > source_length(n) - _length) {
1519                         new_start = source_length(n) - _length;
1520                 }
1521         }
1522         return true;
1523 }
1524
1525 boost::shared_ptr<Region>
1526 Region::get_parent() const
1527 {
1528         boost::shared_ptr<Playlist> pl (playlist());
1529
1530         if (pl) {
1531                 boost::shared_ptr<Region> r;
1532                 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1533
1534                 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1535                         return boost::static_pointer_cast<Region> (r);
1536                 }
1537         }
1538
1539         return boost::shared_ptr<Region>();
1540 }
1541
1542 int
1543 Region::apply (Filter& filter)
1544 {
1545         return filter.run (shared_from_this());
1546 }
1547
1548
1549 void
1550 Region::invalidate_transients ()
1551 {
1552         _valid_transients = false;
1553         _transients.clear ();
1554 }
1555
1556
1557 void
1558 Region::use_sources (SourceList const & s)
1559 {
1560         set<boost::shared_ptr<Source> > unique_srcs;
1561
1562         for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1563                 _sources.push_back (*i);
1564                 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1565                 unique_srcs.insert (*i);
1566         }
1567
1568         for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1569                 _master_sources.push_back (*i);
1570                 if (unique_srcs.find (*i) == unique_srcs.end()) {
1571                         (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1572                 }
1573         }
1574 }
1575