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