Merged with trunk R999.
[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         /* derived classes must call notify_callbacks() and then emit GoingAway */
269 }
270
271 void
272 Region::set_playlist (Playlist* pl)
273 {
274         _playlist = pl;
275 }
276
277 void
278 Region::set_name (string str)
279 {
280         if (_name != str) {
281                 _name = str; 
282                 send_change (NameChanged);
283         }
284 }
285
286 void
287 Region::set_length (nframes_t len, void *src)
288 {
289         if (_flags & Locked) {
290                 return;
291         }
292
293         if (_length != len && len != 0) {
294
295                 /* check that the current _position wouldn't make the new 
296                    length impossible.
297                 */
298
299                 if (max_frames - len < _position) {
300                         return;
301                 }
302
303                 if (!verify_length (len)) {
304                         return;
305                 }
306                 
307                 _length = len;
308
309                 _flags = Region::Flag (_flags & ~WholeFile);
310
311                 first_edit ();
312                 maybe_uncopy ();
313
314                 if (!_frozen) {
315                         recompute_at_end ();
316                 }
317
318                 send_change (LengthChanged);
319         }
320 }
321
322 void
323 Region::maybe_uncopy ()
324 {
325 }
326
327 void
328 Region::first_edit ()
329 {
330         if (_first_edit != EditChangesNothing && _playlist) {
331
332                 _name = _playlist->session().new_region_name (_name);
333                 _first_edit = EditChangesNothing;
334
335                 send_change (NameChanged);
336                 RegionFactory::CheckNewRegion (shared_from_this());
337         }
338 }
339
340 void
341 Region::move_to_natural_position (void *src)
342 {
343         if (!_playlist) {
344                 return;
345         }
346         
347         boost::shared_ptr<Region> whole_file_region = get_parent();
348
349         if (whole_file_region) {
350                 set_position (whole_file_region->position() + _start, src);
351         }
352 }
353         
354 void
355 Region::special_set_position (nframes_t pos)
356 {
357         /* this is used when creating a whole file region as 
358            a way to store its "natural" or "captured" position.
359         */
360
361         _position = pos;
362 }
363
364 void
365 Region::set_position (nframes_t pos, void *src)
366 {
367         if (_flags & Locked) {
368                 return;
369         }
370
371         if (_position != pos) {
372                 _position = pos;
373
374                 /* check that the new _position wouldn't make the current
375                    length impossible - if so, change the length. 
376
377                    XXX is this the right thing to do?
378                 */
379
380                 if (max_frames - _length < _position) {
381                         _length = max_frames - _position;
382                 }
383         }
384
385         /* do this even if the position is the same. this helps out
386            a GUI that has moved its representation already.
387         */
388
389         send_change (PositionChanged);
390 }
391
392 void
393 Region::set_position_on_top (nframes_t pos, void *src)
394 {
395         if (_flags & Locked) {
396                 return;
397         }
398
399         if (_position != pos) {
400                 _position = pos;
401         }
402
403         _playlist->raise_region_to_top (shared_from_this ());
404
405         /* do this even if the position is the same. this helps out
406            a GUI that has moved its representation already.
407         */
408         
409         send_change (PositionChanged);
410 }
411
412 void
413 Region::nudge_position (long n, void *src)
414 {
415         if (_flags & Locked) {
416                 return;
417         }
418
419         if (n == 0) {
420                 return;
421         }
422         
423         if (n > 0) {
424                 if (_position > max_frames - n) {
425                         _position = max_frames;
426                 } else {
427                         _position += n;
428                 }
429         } else {
430                 if (_position < (nframes_t) -n) {
431                         _position = 0;
432                 } else {
433                         _position += n;
434                 }
435         }
436
437         send_change (PositionChanged);
438 }
439
440 void
441 Region::set_start (nframes_t pos, void *src)
442 {
443         if (_flags & Locked) {
444                 return;
445         }
446         /* This just sets the start, nothing else. It effectively shifts
447            the contents of the Region within the overall extent of the Source,
448            without changing the Region's position or length
449         */
450
451         if (_start != pos) {
452
453                 if (!verify_start (pos)) {
454                         return;
455                 }
456
457                 _start = pos;
458                 _flags = Region::Flag (_flags & ~WholeFile);
459                 first_edit ();
460
461                 send_change (StartChanged);
462         }
463 }
464
465 void
466 Region::trim_start (nframes_t new_position, void *src)
467 {
468         if (_flags & Locked) {
469                 return;
470         }
471         nframes_t new_start;
472         int32_t start_shift;
473         
474         if (new_position > _position) {
475                 start_shift = new_position - _position;
476         } else {
477                 start_shift = -(_position - new_position);
478         }
479
480         if (start_shift > 0) {
481
482                 if (_start > max_frames - start_shift) {
483                         new_start = max_frames;
484                 } else {
485                         new_start = _start + start_shift;
486                 }
487
488                 if (!verify_start (new_start)) {
489                         return;
490                 }
491
492         } else if (start_shift < 0) {
493
494                 if (_start < (nframes_t) -start_shift) {
495                         new_start = 0;
496                 } else {
497                         new_start = _start + start_shift;
498                 }
499         } else {
500                 return;
501         }
502
503         if (new_start == _start) {
504                 return;
505         }
506         
507         _start = new_start;
508         _flags = Region::Flag (_flags & ~WholeFile);
509         first_edit ();
510
511         send_change (StartChanged);
512 }
513
514 void
515 Region::trim_front (nframes_t new_position, void *src)
516 {
517         if (_flags & Locked) {
518                 return;
519         }
520
521         nframes_t end = last_frame();
522         nframes_t source_zero;
523
524         if (_position > _start) {
525                 source_zero = _position - _start;
526         } else {
527                 source_zero = 0; // its actually negative, but this will work for us
528         }
529
530         if (new_position < end) { /* can't trim it zero or negative length */
531                 
532                 nframes_t newlen;
533
534                 /* can't trim it back passed where source position zero is located */
535                 
536                 new_position = max (new_position, source_zero);
537                 
538                 
539                 if (new_position > _position) {
540                         newlen = _length - (new_position - _position);
541                 } else {
542                         newlen = _length + (_position - new_position);
543                 }
544                 
545                 trim_to_internal (new_position, newlen, src);
546                 if (!_frozen) {
547                         recompute_at_start ();
548                 }
549         }
550 }
551
552 void
553 Region::trim_end (nframes_t new_endpoint, void *src)
554 {
555         if (_flags & Locked) {
556                 return;
557         }
558
559         if (new_endpoint > _position) {
560                 trim_to_internal (_position, new_endpoint - _position, this);
561                 if (!_frozen) {
562                         recompute_at_end ();
563                 }
564         }
565 }
566
567 void
568 Region::trim_to (nframes_t position, nframes_t length, void *src)
569 {
570         if (_flags & Locked) {
571                 return;
572         }
573
574         trim_to_internal (position, length, src);
575
576         if (!_frozen) {
577                 recompute_at_start ();
578                 recompute_at_end ();
579         }
580 }
581
582 void
583 Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
584 {
585         int32_t start_shift;
586         nframes_t new_start;
587
588         if (_flags & Locked) {
589                 return;
590         }
591
592         if (position > _position) {
593                 start_shift = position - _position;
594         } else {
595                 start_shift = -(_position - position);
596         }
597
598         if (start_shift > 0) {
599
600                 if (_start > max_frames - start_shift) {
601                         new_start = max_frames;
602                 } else {
603                         new_start = _start + start_shift;
604                 }
605
606
607         } else if (start_shift < 0) {
608
609                 if (_start < (nframes_t) -start_shift) {
610                         new_start = 0;
611                 } else {
612                         new_start = _start + start_shift;
613                 }
614         } else {
615                 new_start = _start;
616         }
617
618         if (!verify_start_and_length (new_start, length)) {
619                 return;
620         }
621
622         Change what_changed = Change (0);
623
624         if (_start != new_start) {
625                 _start = new_start;
626                 what_changed = Change (what_changed|StartChanged);
627         }
628         if (_length != length) {
629                 _length = length;
630                 what_changed = Change (what_changed|LengthChanged);
631         }
632         if (_position != position) {
633                 _position = position;
634                 what_changed = Change (what_changed|PositionChanged);
635         }
636         
637         _flags = Region::Flag (_flags & ~WholeFile);
638
639         if (what_changed & (StartChanged|LengthChanged)) {
640                 first_edit ();
641         } 
642
643         if (what_changed) {
644                 send_change (what_changed);
645         }
646 }       
647
648 void
649 Region::set_hidden (bool yn)
650 {
651         if (hidden() != yn) {
652
653                 if (yn) {
654                         _flags = Flag (_flags|Hidden);
655                 } else {
656                         _flags = Flag (_flags & ~Hidden);
657                 }
658
659                 send_change (HiddenChanged);
660         }
661 }
662
663 void
664 Region::set_muted (bool yn)
665 {
666         if (muted() != yn) {
667
668                 if (yn) {
669                         _flags = Flag (_flags|Muted);
670                 } else {
671                         _flags = Flag (_flags & ~Muted);
672                 }
673
674                 send_change (MuteChanged);
675         }
676 }
677
678 void
679 Region::set_opaque (bool yn)
680 {
681         if (opaque() != yn) {
682                 if (yn) {
683                         _flags = Flag (_flags|Opaque);
684                 } else {
685                         _flags = Flag (_flags & ~Opaque);
686                 }
687                 send_change (OpacityChanged);
688         }
689 }
690
691 void
692 Region::set_locked (bool yn)
693 {
694         if (locked() != yn) {
695                 if (yn) {
696                         _flags = Flag (_flags|Locked);
697                 } else {
698                         _flags = Flag (_flags & ~Locked);
699                 }
700                 send_change (LockChanged);
701         }
702 }
703
704 void
705 Region::set_sync_position (nframes_t absolute_pos)
706 {
707         nframes_t file_pos;
708
709         file_pos = _start + (absolute_pos - _position);
710
711         if (file_pos != _sync_position) {
712                 
713                 _sync_position = file_pos;
714                 _flags = Flag (_flags|SyncMarked);
715
716                 if (!_frozen) {
717                         maybe_uncopy ();
718                 }
719                 send_change (SyncOffsetChanged);
720         }
721 }
722
723 void
724 Region::clear_sync_position ()
725 {
726         if (_flags & SyncMarked) {
727                 _flags = Flag (_flags & ~SyncMarked);
728
729                 if (!_frozen) {
730                         maybe_uncopy ();
731                 }
732                 send_change (SyncOffsetChanged);
733         }
734 }
735
736 nframes_t
737 Region::sync_offset (int& dir) const
738 {
739         /* returns the sync point relative the first frame of the region */
740
741         if (_flags & SyncMarked) {
742                 if (_sync_position > _start) {
743                         dir = 1;
744                         return _sync_position - _start; 
745                 } else {
746                         dir = -1;
747                         return _start - _sync_position;
748                 }
749         } else {
750                 dir = 0;
751                 return 0;
752         }
753 }
754
755 nframes_t 
756 Region::adjust_to_sync (nframes_t pos)
757 {
758         int sync_dir;
759         nframes_t offset = sync_offset (sync_dir);
760         
761         if (sync_dir > 0) {
762                 if (max_frames - pos > offset) {
763                         pos += offset;
764                 }
765         } else {
766                 if (pos > offset) {
767                         pos -= offset;
768                 } else {
769                         pos = 0;
770                 }
771         }
772
773         return pos;
774 }
775
776 nframes_t
777 Region::sync_position() const
778 {
779         if (_flags & SyncMarked) {
780                 return _sync_position; 
781         } else {
782                 return _start;
783         }
784 }
785
786
787 void
788 Region::raise ()
789 {
790         if (_playlist == 0) {
791                 return;
792         }
793
794         _playlist->raise_region (shared_from_this ());
795 }
796
797 void
798 Region::lower ()
799 {
800         if (_playlist == 0) {
801                 return;
802         }
803
804         _playlist->lower_region (shared_from_this ());
805 }
806
807 void
808 Region::raise_to_top ()
809 {
810
811         if (_playlist == 0) {
812                 return;
813         }
814
815         _playlist->raise_region_to_top (shared_from_this());
816 }
817
818 void
819 Region::lower_to_bottom ()
820 {
821         if (_playlist == 0) {
822                 return;
823         }
824
825         _playlist->lower_region_to_bottom (shared_from_this());
826 }
827
828 void
829 Region::set_layer (layer_t l)
830 {
831         if (_layer != l) {
832                 _layer = l;
833                 
834                 send_change (LayerChanged);
835         }
836 }
837
838 XMLNode&
839 Region::state (bool full_state)
840 {
841         XMLNode *node = new XMLNode ("Region");
842         char buf[64];
843         char* fe;
844
845         _id.print (buf, sizeof (buf));
846         node->add_property ("id", buf);
847         node->add_property ("name", _name);
848         node->add_property ("type", _type.to_string());
849         snprintf (buf, sizeof (buf), "%u", _start);
850         node->add_property ("start", buf);
851         snprintf (buf, sizeof (buf), "%u", _length);
852         node->add_property ("length", buf);
853         snprintf (buf, sizeof (buf), "%u", _position);
854         node->add_property ("position", buf);
855         
856         switch (_first_edit) {
857         case EditChangesNothing:
858                 fe = X_("nothing");
859                 break;
860         case EditChangesName:
861                 fe = X_("name");
862                 break;
863         case EditChangesID:
864                 fe = X_("id");
865                 break;
866         }
867
868         node->add_property ("first_edit", fe);
869
870         /* note: flags are stored by derived classes */
871
872         snprintf (buf, sizeof (buf), "%d", (int) _layer);
873         node->add_property ("layer", buf);
874         snprintf (buf, sizeof (buf), "%u", _sync_position);
875         node->add_property ("sync-position", buf);
876
877         return *node;
878 }
879
880 XMLNode&
881 Region::get_state ()
882 {
883         return state (true);
884 }
885
886 int
887 Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
888 {
889         const XMLNodeList& nlist = node.children();
890         const XMLProperty *prop;
891         nframes_t val;
892
893         /* this is responsible for setting those aspects of Region state 
894            that are mutable after construction.
895         */
896
897         if ((prop = node.property ("name")) == 0) {
898                 error << _("XMLNode describing a Region is incomplete (no name)") << endmsg;
899                 return -1;
900         }
901
902         _name = prop->value();
903         
904         if ((prop = node.property ("type")) == 0) {
905                 _type = DataType::AUDIO;
906         } else {
907                 _type = DataType(prop->value());
908         }
909
910         if ((prop = node.property ("start")) != 0) {
911                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
912                 if (val != _start) {
913                         what_changed = Change (what_changed|StartChanged);      
914                         _start = val;
915                 }
916         } else {
917                 _start = 0;
918         }
919
920         if ((prop = node.property ("length")) != 0) {
921                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
922                 if (val != _length) {
923                         what_changed = Change (what_changed|LengthChanged);
924                         _length = val;
925                 }
926         } else {
927                 _length = 1;
928         }
929
930         if ((prop = node.property ("position")) != 0) {
931                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
932                 if (val != _position) {
933                         what_changed = Change (what_changed|PositionChanged);
934                         _position = val;
935                 }
936         } else {
937                 _position = 0;
938         }
939
940         if ((prop = node.property ("layer")) != 0) {
941                 layer_t x;
942                 x = (layer_t) atoi (prop->value().c_str());
943                 if (x != _layer) {
944                         what_changed = Change (what_changed|LayerChanged);
945                         _layer = x;
946                 }
947         } else {
948                 _layer = 0;
949         }
950
951         if ((prop = node.property ("sync-position")) != 0) {
952                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
953                 if (val != _sync_position) {
954                         what_changed = Change (what_changed|SyncOffsetChanged);
955                         _sync_position = val;
956                 }
957         } else {
958                 _sync_position = _start;
959         }
960
961         /* XXX FIRST EDIT !!! */
962         
963         /* note: derived classes set flags */
964
965         if (_extra_xml) {
966                 delete _extra_xml;
967                 _extra_xml = 0;
968         }
969
970         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
971                 
972                 XMLNode *child;
973                 
974                 child = (*niter);
975                 
976                 if (child->name () == "extra") {
977                         _extra_xml = new XMLNode (*child);
978                         break;
979                 }
980         }
981
982         if (send) {
983                 send_change (what_changed);
984         }
985
986         return 0;
987 }
988
989 int
990 Region::set_state (const XMLNode& node)
991 {
992         const XMLProperty *prop;
993         Change what_changed = Change (0);
994
995         /* ID is not allowed to change, ever */
996
997         if ((prop = node.property ("id")) == 0) {
998                 error << _("Session: XMLNode describing a Region is incomplete (no id)") << endmsg;
999                 return -1;
1000         }
1001
1002         _id = prop->value();
1003         
1004         _first_edit = EditChangesNothing;
1005         
1006         set_live_state (node, what_changed, true);
1007
1008         return 0;
1009 }
1010
1011 void
1012 Region::freeze ()
1013 {
1014         _frozen++;
1015 }
1016
1017 void
1018 Region::thaw (const string& why)
1019 {
1020         Change what_changed = Change (0);
1021
1022         {
1023                 Glib::Mutex::Lock lm (_lock);
1024
1025                 if (_frozen && --_frozen > 0) {
1026                         return;
1027                 }
1028
1029                 if (_pending_changed) {
1030                         what_changed = _pending_changed;
1031                         _pending_changed = Change (0);
1032                 }
1033         }
1034
1035         if (what_changed == Change (0)) {
1036                 return;
1037         }
1038
1039         if (what_changed & LengthChanged) {
1040                 if (what_changed & PositionChanged) {
1041                         recompute_at_start ();
1042                 } 
1043                 recompute_at_end ();
1044         }
1045                 
1046         StateChanged (what_changed);
1047 }
1048
1049 void
1050 Region::send_change (Change what_changed)
1051 {
1052         {
1053                 Glib::Mutex::Lock lm (_lock);
1054                 if (_frozen) {
1055                         _pending_changed = Change (_pending_changed|what_changed);
1056                         return;
1057                 } 
1058         }
1059
1060         StateChanged (what_changed);
1061 }
1062
1063 void
1064 Region::set_last_layer_op (uint64_t when)
1065 {
1066         _last_layer_op = when;
1067 }
1068
1069 bool
1070 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1071 {
1072         return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1073 }
1074
1075 bool
1076 Region::equivalent (boost::shared_ptr<const Region> other) const
1077 {
1078         return _start == other->_start &&
1079                 _position == other->_position &&
1080                 _length == other->_length;
1081 }
1082
1083 bool
1084 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1085 {
1086         return _start == other->_start &&
1087                 _length == other->_length;
1088 }
1089
1090 bool
1091 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1092 {
1093         return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1094 }
1095
1096 void
1097 Region::source_deleted (boost::shared_ptr<Source>)
1098 {
1099         delete this;
1100 }
1101
1102 vector<string>
1103 Region::master_source_names ()
1104 {
1105         SourceList::iterator i;
1106
1107         vector<string> names;
1108         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1109                 names.push_back((*i)->name());
1110         }
1111
1112         return names;
1113 }
1114
1115 bool
1116 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1117 {
1118         if (!other)
1119                 return false;
1120
1121         SourceList::const_iterator i;
1122         SourceList::const_iterator io;
1123
1124         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1125                 if ((*i)->id() != (*io)->id()) {
1126                         return false;
1127                 }
1128         }
1129
1130         for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1131                 if ((*i)->id() != (*io)->id()) {
1132                         return false;
1133                 }
1134         }
1135
1136         return true;
1137 }
1138
1139 bool
1140 Region::verify_length (jack_nframes_t len)
1141 {
1142         for (uint32_t n=0; n < _sources.size(); ++n) {
1143                 if (_start > _sources[n]->length() - len) {
1144                         return false;
1145                 }
1146         }
1147         return true;
1148 }
1149
1150 bool
1151 Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
1152 {
1153         for (uint32_t n=0; n < _sources.size(); ++n) {
1154                 if (new_length > _sources[n]->length() - new_start) {
1155                         return false;
1156                 }
1157         }
1158         return true;
1159 }
1160 bool
1161 Region::verify_start (jack_nframes_t pos)
1162 {
1163         for (uint32_t n=0; n < _sources.size(); ++n) {
1164                 if (pos > _sources[n]->length() - _length) {
1165                         return false;
1166                 }
1167         }
1168         return true;
1169 }
1170
1171 bool
1172 Region::verify_start_mutable (jack_nframes_t& new_start)
1173 {
1174         for (uint32_t n=0; n < _sources.size(); ++n) {
1175                 if (new_start > _sources[n]->length() - _length) {
1176                         new_start = _sources[n]->length() - _length;
1177                 }
1178         }
1179         return true;
1180 }
1181
1182 boost::shared_ptr<Region>
1183 Region::get_parent()
1184 {
1185         boost::shared_ptr<Region> r;
1186
1187         if (_playlist) {
1188                 r = _playlist->session().find_whole_file_parent (*this);
1189         }
1190         
1191         return r;
1192 }
1193