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