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