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