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