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