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