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