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