e9b896f26e9ee8fbdb54d6f8585f68e532555703
[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 */
19
20 #include <iostream>
21 #include <cmath>
22 #include <climits>
23 #include <algorithm>
24 #include <sstream>
25
26
27 #include <glibmm/thread.h>
28 #include "pbd/xml++.h"
29 #include "pbd/stacktrace.h"
30 #include "pbd/enumwriter.h"
31
32 #include "ardour/debug.h"
33 #include "ardour/region.h"
34 #include "ardour/playlist.h"
35 #include "ardour/session.h"
36 #include "ardour/source.h"
37 #include "ardour/tempo.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/filter.h"
40 #include "ardour/profile.h"
41 #include "ardour/utils.h"
42
43 #include "i18n.h"
44
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48
49 Change Region::FadeChanged       = ARDOUR::new_change ();
50 Change Region::SyncOffsetChanged = ARDOUR::new_change ();
51 Change Region::MuteChanged       = ARDOUR::new_change ();
52 Change Region::OpacityChanged    = ARDOUR::new_change ();
53 Change Region::LockChanged       = ARDOUR::new_change ();
54 Change Region::LayerChanged      = ARDOUR::new_change ();
55 Change Region::HiddenChanged     = ARDOUR::new_change ();
56
57 PBD::Signal1<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
58
59 void
60 Region::register_states ()
61 {
62         _xml_node_name = X_("Region");
63         add_state (_start);
64         add_state (_position);
65         add_state (_layer);
66 }
67
68 /* derived-from-derived constructor (no sources in constructor) */
69 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
70         : SessionObject(s, name)
71         , _type(type)
72         , _flags(Flag (flags|DoNotSendPropertyChanges))
73         , _start (X_("start"), start)
74         , _length(length)
75         , _position (X_("position"), 0)
76         , _last_position(0)
77         , _positional_lock_style(AudioTime)
78         , _sync_position(_start)
79         , _layer (X_("layer"), layer)
80         , _first_edit(EditChangesNothing)
81         , _frozen(0)
82         , _ancestral_start (0)
83         , _ancestral_length (0)
84         , _stretch(1.0)
85         , _shift(1.0)
86         , _read_data_count(0)
87         , _pending_changed(Change (0))
88         , _last_layer_op(0)
89         , _pending_explicit_relayer (false)
90 {
91         register_states ();
92         
93         /* no sources at this point */
94 }
95
96 /** Basic Region constructor (single source) */
97 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
98         : SessionObject(src->session(), name)
99         , _type(type)
100         , _flags(Flag (flags|DoNotSendPropertyChanges))
101         , _start (X_("start"), start)
102         , _length(length)
103         , _position (X_("position"), 0)
104         , _last_position(0)
105         , _positional_lock_style(AudioTime)
106         , _sync_position(_start)
107         , _layer (X_("layer"), layer)
108         , _first_edit(EditChangesNothing)
109         , _frozen(0)
110         , _ancestral_start (0)
111         , _ancestral_length (0)
112         , _stretch (1.0)
113         , _shift (1.0)
114         , _valid_transients(false)
115         , _read_data_count(0)
116         , _pending_changed(Change (0))
117         , _last_layer_op(0)
118         , _pending_explicit_relayer (false)
119 {
120         register_states ();
121
122         _sources.push_back (src);
123         _master_sources.push_back (src);
124
125         src->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
126
127         assert(_sources.size() > 0);
128         _positional_lock_style = AudioTime;
129 }
130
131 /** Basic Region constructor (many sources) */
132 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
133         : SessionObject(srcs.front()->session(), name)
134         , _type(type)
135         , _flags(Flag (flags|DoNotSendPropertyChanges))
136         , _start (X_("start"), start)
137         , _length(length)
138         , _position (X_("position"), 0)
139         , _last_position(0)
140         , _positional_lock_style(AudioTime)
141         , _sync_position(_start)
142         , _layer (X_("layer"), layer)
143         , _first_edit(EditChangesNothing)
144         , _frozen(0)
145         , _ancestral_start (0)
146         , _ancestral_length (0)
147         , _stretch(1.0)
148         , _shift(1.0)
149         , _read_data_count(0)
150         , _pending_changed(Change (0))
151         , _last_layer_op(0)
152         , _pending_explicit_relayer (false)
153 {
154         register_states ();
155
156         use_sources (srcs);
157         assert(_sources.size() > 0);
158 }
159
160 /** Create a new Region from part of an existing one */
161 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
162         : SessionObject(other->session(), name)
163         , _type (other->data_type())
164         , _start (X_("start"), 0)
165         , _position (X_("position"), 0)
166         , _layer (X_("layer"), 0)
167         , _pending_explicit_relayer (false)
168
169 {
170         register_states ();
171
172         _start = other->_start + offset;
173         copy_stuff (other, offset, length, name, layer, flags);
174
175         _flags = Flag (_flags | DoNotSendPropertyChanges);
176
177         /* if the other region had a distinct sync point
178            set, then continue to use it as best we can.
179            otherwise, reset sync point back to start.
180         */
181
182         if (other->flags() & SyncMarked) {
183                 if (other->_sync_position < _start) {
184                         _flags = Flag (_flags & ~SyncMarked);
185                         _sync_position = _start;
186                 } else {
187                         _sync_position = other->_sync_position;
188                 }
189         } else {
190                 _flags = Flag (_flags & ~SyncMarked);
191                 _sync_position = _start;
192         }
193
194         if (Profile->get_sae()) {
195                 /* reset sync point to start if its ended up
196                    outside region bounds.
197                 */
198
199                 if (_sync_position < _start || _sync_position >= _start + _length) {
200                         _flags = Flag (_flags & ~SyncMarked);
201                         _sync_position = _start;
202                 }
203         }
204 }
205
206 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
207         : SessionObject(other->session(), name)
208         , _type (other->data_type())
209         , _start (X_("start"), 0)
210         , _position (X_("position"), 0)
211         , _layer (X_("layer"), 0)
212         , _pending_explicit_relayer (false)
213 {
214         register_states ();
215
216         /* create a new Region exactly like another but starting at 0 in its sources */
217
218         _start = 0;
219         copy_stuff (other, 0, length, name, layer, flags);
220
221         _flags = Flag (_flags | DoNotSendPropertyChanges);
222
223         /* sync pos is relative to start of file. our start-in-file is now zero,
224            so set our sync position to whatever the the difference between
225            _start and _sync_pos was in the other region.
226
227            result is that our new sync pos points to the same point in our source(s)
228            as the sync in the other region did in its source(s).
229
230            since we start at zero in our source(s), it is not possible to use a sync point that
231            is before the start. reset it to _start if that was true in the other region.
232         */
233
234         if (other->flags() & SyncMarked) {
235                 if (other->_start < other->_sync_position) {
236                         /* sync pos was after the start point of the other region */
237                         _sync_position = other->_sync_position - other->_start;
238                 } else {
239                         /* sync pos was before the start point of the other region. not possible here. */
240                         _flags = Flag (_flags & ~SyncMarked);
241                         _sync_position = _start;
242                 }
243         } else {
244                 _flags = Flag (_flags & ~SyncMarked);
245                 _sync_position = _start;
246         }
247
248         if (Profile->get_sae()) {
249                 /* reset sync point to start if its ended up
250                    outside region bounds.
251                 */
252
253                 if (_sync_position < _start || _sync_position >= _start + _length) {
254                         _flags = Flag (_flags & ~SyncMarked);
255                         _sync_position = _start;
256                 }
257         }
258
259         /* reset a couple of things that copy_stuff() gets wrong in this particular case */
260
261         _positional_lock_style = other->_positional_lock_style;
262         _first_edit = other->_first_edit;
263 }
264
265 /** Pure copy constructor */
266 Region::Region (boost::shared_ptr<const Region> other)
267         : SessionObject(other->session(), other->name())
268         , _type(other->data_type())
269         , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
270         , _start(other->_start)
271         , _length(other->_length)
272         , _position(other->_position)
273         , _last_position(other->_last_position)
274         , _positional_lock_style(other->_positional_lock_style)
275         , _sync_position(other->_sync_position)
276         , _layer(other->_layer)
277         , _first_edit(EditChangesID)
278         , _frozen(0)
279         , _ancestral_start (other->_ancestral_start)
280         , _ancestral_length (other->_ancestral_length)
281         , _stretch (other->_stretch)
282         , _shift (other->_shift)
283         , _valid_transients(false)
284         , _read_data_count(0)
285         , _pending_changed(Change(0))
286         , _last_layer_op(other->_last_layer_op)
287         , _pending_explicit_relayer (false)
288 {
289         register_states ();
290
291         _flags = Flag (_flags | DoNotSendPropertyChanges);
292
293         other->_first_edit = EditChangesName;
294
295         if (other->_extra_xml) {
296                 _extra_xml = new XMLNode (*other->_extra_xml);
297         } else {
298                 _extra_xml = 0;
299         }
300
301         use_sources (other->_sources);
302         assert(_sources.size() > 0);
303 }
304
305 Region::Region (const SourceList& srcs, const XMLNode& node)
306         : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
307         , _type(DataType::NIL) // to be loaded from XML
308         , _flags(DoNotSendPropertyChanges)
309         , _start (X_("start"), 0)
310         , _length(0)
311         , _position (X_("position"), 0)
312         , _last_position(0)
313         , _positional_lock_style(AudioTime)
314         , _sync_position(_start)
315         , _layer (X_("layer"), 0)
316         , _first_edit(EditChangesNothing)
317         , _frozen(0)
318         , _stretch(1.0)
319         , _shift(1.0)
320         , _read_data_count(0)
321         , _pending_changed(Change(0))
322         , _last_layer_op(0)
323         , _pending_explicit_relayer (false)
324 {
325         register_states ();
326
327         use_sources (srcs);
328
329         if (set_state (node, Stateful::loading_state_version)) {
330                 throw failed_constructor();
331         }
332
333         assert(_type != DataType::NIL);
334         assert(_sources.size() > 0);
335 }
336
337 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
338         : SessionObject(src->session(), X_("error: XML did not reset this"))
339         , _type(DataType::NIL)
340         , _flags(DoNotSendPropertyChanges)
341         , _start (X_("start"), 0)
342         , _length(0)
343         , _position (X_("position"), 0)
344         , _last_position(0)
345         , _positional_lock_style(AudioTime)
346         , _sync_position(_start)
347         , _layer (X_("layer"), 0)
348         , _first_edit(EditChangesNothing)
349         , _frozen(0)
350         , _stretch(1.0)
351         , _shift(1.0)
352         , _read_data_count(0)
353         , _pending_changed(Change(0))
354         , _last_layer_op(0)
355         , _pending_explicit_relayer (false)
356 {
357         register_states ();
358
359         _sources.push_back (src);
360
361         if (set_state (node, Stateful::loading_state_version)) {
362                 throw failed_constructor();
363         }
364
365         assert(_type != DataType::NIL);
366         assert(_sources.size() > 0);
367 }
368
369 Region::~Region ()
370 {
371         DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
372 }
373
374 void
375 Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
376 {
377         _frozen = 0;
378         _pending_changed = Change (0);
379         _read_data_count = 0;
380         _valid_transients = false;
381
382         _length = length;
383         _last_length = length;
384         _sync_position = other->_sync_position;
385         _ancestral_start = other->_ancestral_start;
386         _ancestral_length = other->_ancestral_length;
387         _stretch = other->_stretch;
388         _shift = other->_shift;
389         _name = name;
390         _last_position = 0;
391         _position = 0;
392         _layer = layer;
393         _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
394         _first_edit = EditChangesNothing;
395         _last_layer_op = 0;
396         _positional_lock_style = AudioTime;
397
398         use_sources (other->_sources);
399 }
400
401 void
402 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
403 {
404         _playlist = wpl.lock();
405 }
406
407 bool
408 Region::set_name (const std::string& str)
409 {
410         if (_name != str) {
411                 SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
412                 assert(_name == str);
413                 send_change (ARDOUR::NameChanged);
414         }
415
416         return true;
417 }
418
419 void
420 Region::set_length (nframes_t len, void */*src*/)
421 {
422         //cerr << "Region::set_length() len = " << len << endl;
423         if (_flags & Locked) {
424                 return;
425         }
426
427         if (_length != len && len != 0) {
428
429                 /* check that the current _position wouldn't make the new
430                    length impossible.
431                 */
432
433                 if (max_frames - len < _position) {
434                         return;
435                 }
436
437                 if (!verify_length (len)) {
438                         return;
439                 }
440
441
442                 _last_length = _length;
443                 _length = len;
444
445                 _flags = Region::Flag (_flags & ~WholeFile);
446
447                 first_edit ();
448                 maybe_uncopy ();
449                 invalidate_transients ();
450
451                 if (!_frozen) {
452                         recompute_at_end ();
453                 }
454
455                 send_change (LengthChanged);
456         }
457 }
458
459 void
460 Region::maybe_uncopy ()
461 {
462 }
463
464 void
465 Region::first_edit ()
466 {
467         boost::shared_ptr<Playlist> pl (playlist());
468
469         if (_first_edit != EditChangesNothing && pl) {
470
471                 _name = _session.new_region_name (_name);
472                 _first_edit = EditChangesNothing;
473
474                 send_change (ARDOUR::NameChanged);
475                 RegionFactory::CheckNewRegion (shared_from_this());
476         }
477 }
478
479 bool
480 Region::at_natural_position () const
481 {
482         boost::shared_ptr<Playlist> pl (playlist());
483
484         if (!pl) {
485                 return false;
486         }
487
488         boost::shared_ptr<Region> whole_file_region = get_parent();
489
490         if (whole_file_region) {
491                 if (_position == whole_file_region->position() + _start) {
492                         return true;
493                 }
494         }
495
496         return false;
497 }
498
499 void
500 Region::move_to_natural_position (void *src)
501 {
502         boost::shared_ptr<Playlist> pl (playlist());
503
504         if (!pl) {
505                 return;
506         }
507
508         boost::shared_ptr<Region> whole_file_region = get_parent();
509
510         if (whole_file_region) {
511                 set_position (whole_file_region->position() + _start, src);
512         }
513 }
514
515 void
516 Region::special_set_position (nframes_t pos)
517 {
518         /* this is used when creating a whole file region as
519            a way to store its "natural" or "captured" position.
520         */
521
522         _position = _position;
523         _position = pos;
524 }
525
526 void
527 Region::set_position_lock_style (PositionLockStyle ps)
528 {
529         boost::shared_ptr<Playlist> pl (playlist());
530
531         if (!pl) {
532                 return;
533         }
534
535         _positional_lock_style = ps;
536
537         if (_positional_lock_style == MusicTime) {
538                 _session.tempo_map().bbt_time (_position, _bbt_time);
539         }
540
541 }
542
543 void
544 Region::update_position_after_tempo_map_change ()
545 {
546         boost::shared_ptr<Playlist> pl (playlist());
547
548         if (!pl || _positional_lock_style != MusicTime) {
549                 return;
550         }
551
552         TempoMap& map (_session.tempo_map());
553         nframes_t pos = map.frame_time (_bbt_time);
554         set_position_internal (pos, false);
555 }
556
557 void
558 Region::set_position (nframes_t pos, void* /*src*/)
559 {
560         if (!can_move()) {
561                 return;
562         }
563
564         set_position_internal (pos, true);
565 }
566
567 void
568 Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
569 {
570         if (_position != pos) {
571                 _last_position = _position;
572                 _position = pos;
573
574                 /* check that the new _position wouldn't make the current
575                    length impossible - if so, change the length.
576
577                    XXX is this the right thing to do?
578                 */
579
580                 if (max_frames - _length < _position) {
581                         _last_length = _length;
582                         _length = max_frames - _position;
583                 }
584
585                 if (allow_bbt_recompute) {
586                         recompute_position_from_lock_style ();
587                 }
588
589                 invalidate_transients ();
590         }
591
592         /* do this even if the position is the same. this helps out
593            a GUI that has moved its representation already.
594         */
595
596         send_change (PositionChanged);
597 }
598
599 void
600 Region::set_position_on_top (nframes_t pos, void* /*src*/)
601 {
602         if (_flags & Locked) {
603                 return;
604         }
605
606         if (_position != pos) {
607                 _last_position = _position;
608                 _position = pos;
609         }
610
611         boost::shared_ptr<Playlist> pl (playlist());
612
613         if (pl) {
614                 pl->raise_region_to_top (shared_from_this ());
615         }
616
617         /* do this even if the position is the same. this helps out
618            a GUI that has moved its representation already.
619         */
620
621         send_change (PositionChanged);
622 }
623
624 void
625 Region::recompute_position_from_lock_style ()
626 {
627         if (_positional_lock_style == MusicTime) {
628                 _session.tempo_map().bbt_time (_position, _bbt_time);
629         }
630 }
631
632 void
633 Region::nudge_position (nframes64_t n, void* /*src*/)
634 {
635         if (_flags & Locked) {
636                 return;
637         }
638
639         if (n == 0) {
640                 return;
641         }
642
643         _last_position = _position;
644
645         if (n > 0) {
646                 if (_position > max_frames - n) {
647                         _position = max_frames;
648                 } else {
649                         _position += n;
650                 }
651         } else {
652                 if (_position < (nframes_t) -n) {
653                         _position = 0;
654                 } else {
655                         _position += n;
656                 }
657         }
658
659         send_change (PositionChanged);
660 }
661
662 void
663 Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
664 {
665         _ancestral_length = l;
666         _ancestral_start = s;
667         _stretch = st;
668         _shift = sh;
669 }
670
671 void
672 Region::set_start (nframes_t pos, void* /*src*/)
673 {
674         if (_flags & (Locked|PositionLocked)) {
675                 return;
676         }
677         /* This just sets the start, nothing else. It effectively shifts
678            the contents of the Region within the overall extent of the Source,
679            without changing the Region's position or length
680         */
681
682         if (_start != pos) {
683
684                 if (!verify_start (pos)) {
685                         return;
686                 }
687
688                 _start = pos;
689                 _flags = Region::Flag (_flags & ~WholeFile);
690                 first_edit ();
691                 invalidate_transients ();
692
693                 send_change (StartChanged);
694         }
695 }
696
697 void
698 Region::trim_start (nframes_t new_position, void */*src*/)
699 {
700         if (_flags & (Locked|PositionLocked)) {
701                 return;
702         }
703         nframes_t new_start;
704         int32_t start_shift;
705
706         if (new_position > _position) {
707                 start_shift = new_position - _position;
708         } else {
709                 start_shift = -(_position - new_position);
710         }
711
712         if (start_shift > 0) {
713
714                 if (_start > max_frames - start_shift) {
715                         new_start = max_frames;
716                 } else {
717                         new_start = _start + start_shift;
718                 }
719
720                 if (!verify_start (new_start)) {
721                         return;
722                 }
723
724         } else if (start_shift < 0) {
725
726                 if (_start < (nframes_t) -start_shift) {
727                         new_start = 0;
728                 } else {
729                         new_start = _start + start_shift;
730                 }
731         } else {
732                 return;
733         }
734
735         if (new_start == _start) {
736                 return;
737         }
738
739         _start = new_start;
740         _flags = Region::Flag (_flags & ~WholeFile);
741         first_edit ();
742
743         send_change (StartChanged);
744 }
745
746 void
747 Region::trim_front (nframes_t new_position, void *src)
748 {
749         if (_flags & Locked) {
750                 return;
751         }
752
753         nframes_t end = last_frame();
754         nframes_t source_zero;
755
756         if (_position > _start) {
757                 source_zero = _position - _start;
758         } else {
759                 source_zero = 0; // its actually negative, but this will work for us
760         }
761
762         if (new_position < end) { /* can't trim it zero or negative length */
763
764                 nframes_t newlen;
765
766                 /* can't trim it back passed where source position zero is located */
767
768                 new_position = max (new_position, source_zero);
769
770
771                 if (new_position > _position) {
772                         newlen = _length - (new_position - _position);
773                 } else {
774                         newlen = _length + (_position - new_position);
775                 }
776
777                 trim_to_internal (new_position, newlen, src);
778                 if (!_frozen) {
779                         recompute_at_start ();
780                 }
781         }
782 }
783
784 /** @param new_endpoint New region end point, such that, for example,
785  *  a region at 0 of length 10 has an endpoint of 9.
786  */
787
788 void
789 Region::trim_end (nframes_t new_endpoint, void */*src*/)
790 {
791         if (_flags & Locked) {
792                 return;
793         }
794
795         if (new_endpoint > _position) {
796                 trim_to_internal (_position, new_endpoint - _position + 1, this);
797                 if (!_frozen) {
798                         recompute_at_end ();
799                 }
800         }
801 }
802
803 void
804 Region::trim_to (nframes_t position, nframes_t length, void *src)
805 {
806         if (_flags & Locked) {
807                 return;
808         }
809
810         trim_to_internal (position, length, src);
811
812         if (!_frozen) {
813                 recompute_at_start ();
814                 recompute_at_end ();
815         }
816 }
817
818 void
819 Region::trim_to_internal (nframes_t position, nframes_t length, void */*src*/)
820 {
821         int32_t start_shift;
822         nframes_t new_start;
823
824         if (_flags & Locked) {
825                 return;
826         }
827
828         if (position > _position) {
829                 start_shift = position - _position;
830         } else {
831                 start_shift = -(_position - position);
832         }
833
834         if (start_shift > 0) {
835
836                 if (_start > max_frames - start_shift) {
837                         new_start = max_frames;
838                 } else {
839                         new_start = _start + start_shift;
840                 }
841
842
843         } else if (start_shift < 0) {
844
845                 if (_start < (nframes_t) -start_shift) {
846                         new_start = 0;
847                 } else {
848                         new_start = _start + start_shift;
849                 }
850         } else {
851                 new_start = _start;
852         }
853
854         if (!verify_start_and_length (new_start, length)) {
855                 return;
856         }
857
858         Change what_changed = Change (0);
859
860         if (_start != new_start) {
861                 _start = new_start;
862                 what_changed = Change (what_changed|StartChanged);
863         }
864         if (_length != length) {
865                 if (!_frozen) {
866                         _last_length = _length;
867                 }
868                 _length = length;
869                 what_changed = Change (what_changed|LengthChanged);
870         }
871         if (_position != position) {
872                 if (!_frozen) {
873                         _last_position = _position;
874                 }
875                 _position = position;
876                 what_changed = Change (what_changed|PositionChanged);
877         }
878
879         _flags = Region::Flag (_flags & ~WholeFile);
880
881         if (what_changed & (StartChanged|LengthChanged)) {
882                 first_edit ();
883         }
884
885         if (what_changed) {
886                 send_change (what_changed);
887         }
888 }
889
890 void
891 Region::set_hidden (bool yn)
892 {
893         if (hidden() != yn) {
894
895                 if (yn) {
896                         _flags = Flag (_flags|Hidden);
897                 } else {
898                         _flags = Flag (_flags & ~Hidden);
899                 }
900
901                 send_change (HiddenChanged);
902         }
903 }
904
905 void
906 Region::set_muted (bool yn)
907 {
908         if (muted() != yn) {
909
910                 if (yn) {
911                         _flags = Flag (_flags|Muted);
912                 } else {
913                         _flags = Flag (_flags & ~Muted);
914                 }
915
916                 send_change (MuteChanged);
917         }
918 }
919
920 void
921 Region::set_opaque (bool yn)
922 {
923         if (opaque() != yn) {
924                 if (yn) {
925                         _flags = Flag (_flags|Opaque);
926                 } else {
927                         _flags = Flag (_flags & ~Opaque);
928                 }
929                 send_change (OpacityChanged);
930         }
931 }
932
933 void
934 Region::set_locked (bool yn)
935 {
936         if (locked() != yn) {
937                 if (yn) {
938                         _flags = Flag (_flags|Locked);
939                 } else {
940                         _flags = Flag (_flags & ~Locked);
941                 }
942                 send_change (LockChanged);
943         }
944 }
945
946 void
947 Region::set_position_locked (bool yn)
948 {
949         if (position_locked() != yn) {
950                 if (yn) {
951                         _flags = Flag (_flags|PositionLocked);
952                 } else {
953                         _flags = Flag (_flags & ~PositionLocked);
954                 }
955                 send_change (LockChanged);
956         }
957 }
958
959 void
960 Region::set_sync_position (nframes_t absolute_pos)
961 {
962         nframes_t const file_pos = _start + (absolute_pos - _position);
963
964         if (file_pos != _sync_position) {
965
966                 _sync_position = file_pos;
967                 _flags = Flag (_flags|SyncMarked);
968
969                 if (!_frozen) {
970                         maybe_uncopy ();
971                 }
972                 send_change (SyncOffsetChanged);
973         }
974 }
975
976 void
977 Region::clear_sync_position ()
978 {
979         if (_flags & SyncMarked) {
980                 _flags = Flag (_flags & ~SyncMarked);
981
982                 if (!_frozen) {
983                         maybe_uncopy ();
984                 }
985                 send_change (SyncOffsetChanged);
986         }
987 }
988
989 nframes_t
990 Region::sync_offset (int& dir) const
991 {
992         /* returns the sync point relative the first frame of the region */
993
994         if (_flags & SyncMarked) {
995                 if (_sync_position > _start) {
996                         dir = 1;
997                         return _sync_position - _start;
998                 } else {
999                         dir = -1;
1000                         return _start - _sync_position;
1001                 }
1002         } else {
1003                 dir = 0;
1004                 return 0;
1005         }
1006 }
1007
1008 nframes_t
1009 Region::adjust_to_sync (nframes_t pos) const
1010 {
1011         int sync_dir;
1012         nframes_t offset = sync_offset (sync_dir);
1013
1014         // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
1015
1016         if (sync_dir > 0) {
1017                 if (pos > offset) {
1018                         pos -= offset;
1019                 } else {
1020                         pos = 0;
1021                 }
1022         } else {
1023                 if (max_frames - pos > offset) {
1024                         pos += offset;
1025                 }
1026         }
1027
1028         return pos;
1029 }
1030
1031 nframes_t
1032 Region::sync_position() const
1033 {
1034         if (_flags & SyncMarked) {
1035                 return _sync_position;
1036         } else {
1037                 return _start;
1038         }
1039 }
1040
1041 void
1042 Region::raise ()
1043 {
1044         boost::shared_ptr<Playlist> pl (playlist());
1045         if (pl) {
1046                 pl->raise_region (shared_from_this ());
1047         }
1048 }
1049
1050 void
1051 Region::lower ()
1052 {
1053         boost::shared_ptr<Playlist> pl (playlist());
1054         if (pl) {
1055                 pl->lower_region (shared_from_this ());
1056         }
1057 }
1058
1059
1060 void
1061 Region::raise_to_top ()
1062 {
1063         boost::shared_ptr<Playlist> pl (playlist());
1064         if (pl) {
1065                 pl->raise_region_to_top (shared_from_this());
1066         }
1067 }
1068
1069 void
1070 Region::lower_to_bottom ()
1071 {
1072         boost::shared_ptr<Playlist> pl (playlist());
1073         if (pl) {
1074                 pl->lower_region_to_bottom (shared_from_this());
1075         }
1076 }
1077
1078 void
1079 Region::set_layer (layer_t l)
1080 {
1081         if (_layer != l) {
1082                 _layer = l;
1083
1084                 send_change (LayerChanged);
1085         }
1086 }
1087
1088 XMLNode&
1089 Region::state (bool /*full_state*/)
1090 {
1091         XMLNode *node = new XMLNode ("Region");
1092         char buf[64];
1093         const char* fe = NULL;
1094
1095         _id.print (buf, sizeof (buf));
1096         node->add_property ("id", buf);
1097         node->add_property ("name", _name);
1098         node->add_property ("type", _type.to_string());
1099         snprintf (buf, sizeof (buf), "%u", _start.get ());
1100         node->add_property ("start", buf);
1101         snprintf (buf, sizeof (buf), "%u", _length);
1102         node->add_property ("length", buf);
1103         snprintf (buf, sizeof (buf), "%u", _position.get ());
1104         node->add_property ("position", buf);
1105         snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
1106         node->add_property ("ancestral-start", buf);
1107         snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
1108         node->add_property ("ancestral-length", buf);
1109         snprintf (buf, sizeof (buf), "%.12g", _stretch);
1110         node->add_property ("stretch", buf);
1111         snprintf (buf, sizeof (buf), "%.12g", _shift);
1112         node->add_property ("shift", buf);
1113
1114         switch (_first_edit) {
1115         case EditChangesNothing:
1116                 fe = X_("nothing");
1117                 break;
1118         case EditChangesName:
1119                 fe = X_("name");
1120                 break;
1121         case EditChangesID:
1122                 fe = X_("id");
1123                 break;
1124         default: /* should be unreachable but makes g++ happy */
1125                 fe = X_("nothing");
1126                 break;
1127         }
1128
1129         node->add_property ("first-edit", fe);
1130
1131         /* note: flags are stored by derived classes */
1132
1133         snprintf (buf, sizeof (buf), "%d", (int) _layer.get());
1134         node->add_property ("layer", buf);
1135         snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
1136         node->add_property ("sync-position", buf);
1137
1138         if (_positional_lock_style != AudioTime) {
1139                 node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
1140                 stringstream str;
1141                 str << _bbt_time;
1142                 node->add_property ("bbt-position", str.str());
1143         }
1144
1145         return *node;
1146 }
1147
1148 XMLNode&
1149 Region::get_state ()
1150 {
1151         return state (true);
1152 }
1153
1154 int
1155 Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
1156 {
1157         const XMLNodeList& nlist = node.children();
1158         const XMLProperty *prop;
1159         nframes_t val;
1160
1161         /* this is responsible for setting those aspects of Region state
1162            that are mutable after construction.
1163         */
1164
1165         if ((prop = node.property ("name"))) {
1166                 _name = prop->value();
1167         }
1168
1169         if ((prop = node.property ("type")) == 0) {
1170                 _type = DataType::AUDIO;
1171         } else {
1172                 _type = DataType(prop->value());
1173         }
1174
1175         if ((prop = node.property ("start")) != 0) {
1176                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1177                 if (val != _start) {
1178                         what_changed = Change (what_changed|StartChanged);
1179                         cerr << _name << " start changed\n";
1180                         _start = val;
1181                 }
1182         }
1183
1184         if ((prop = node.property ("length")) != 0) {
1185                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1186                 if (val != _length) {
1187                         what_changed = Change (what_changed|LengthChanged);
1188                         cerr << _name << " length changed\n";
1189                         _last_length = _length;
1190                         _length = val;
1191                 }
1192         }
1193
1194         if ((prop = node.property ("position")) != 0) {
1195                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1196                 if (val != _position) {
1197                         what_changed = Change (what_changed|PositionChanged);
1198                         cerr << _name << " position changed\n";
1199                         _last_position = _position;
1200                         _position = val;
1201                 }
1202         }
1203
1204         if ((prop = node.property ("layer")) != 0) {
1205                 layer_t x;
1206                 x = (layer_t) atoi (prop->value().c_str());
1207                 if (x != _layer) {
1208                         what_changed = Change (what_changed|LayerChanged);
1209                         cerr << _name << " layer changed\n";
1210                         _layer = x;
1211                 }
1212         }
1213
1214         if ((prop = node.property ("sync-position")) != 0) {
1215                 sscanf (prop->value().c_str(), "%" PRIu32, &val);
1216                 if (val != _sync_position) {
1217                         what_changed = Change (what_changed|SyncOffsetChanged);
1218                         cerr << _name << " sync changed\n";
1219                         _sync_position = val;
1220                 }
1221         }
1222
1223         if ((prop = node.property ("positional-lock-style")) != 0) {
1224                 _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
1225
1226                 if (_positional_lock_style == MusicTime) {
1227                         if ((prop = node.property ("bbt-position")) == 0) {
1228                                 /* missing BBT info, revert to audio time locking */
1229                                 _positional_lock_style = AudioTime;
1230                         } else {
1231                                 if (sscanf (prop->value().c_str(), "%d|%d|%d",
1232                                             &_bbt_time.bars,
1233                                             &_bbt_time.beats,
1234                                             &_bbt_time.ticks) != 3) {
1235                                         _positional_lock_style = AudioTime;
1236                                 }
1237                         }
1238                 }
1239
1240         }
1241
1242         /* XXX FIRST EDIT !!! */
1243
1244         /* these 3 properties never change as a result of any editing */
1245
1246         if ((prop = node.property ("ancestral-start")) != 0) {
1247                 _ancestral_start = strtoll (prop->value().c_str(), 0, 10);
1248         } else {
1249                 _ancestral_start = _start;
1250         }
1251
1252         if ((prop = node.property ("ancestral-length")) != 0) {
1253                 _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
1254         } else {
1255                 _ancestral_length = _length;
1256         }
1257
1258         if ((prop = node.property ("stretch")) != 0) {
1259                 _stretch = atof (prop->value());
1260
1261                 /* fix problem with old sessions corrupted by an impossible
1262                    value for _stretch
1263                 */
1264                 if (_stretch == 0.0) {
1265                         _stretch = 1.0;
1266                 }
1267         } else {
1268                 _stretch = 1.0;
1269         }
1270
1271         if ((prop = node.property ("shift")) != 0) {
1272                 _shift = atof (prop->value());
1273
1274                 /* fix problem with old sessions corrupted by an impossible
1275                    value for _shift
1276                 */
1277                 if (_shift == 0.0) {
1278                         _shift = 1.0;
1279                 }
1280         } else {
1281                 _shift = 1.0;
1282         }
1283
1284
1285         /* note: derived classes set flags */
1286
1287         for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1288
1289                 XMLNode *child;
1290
1291                 child = (*niter);
1292
1293                 if (child->name () == "Extra") {
1294                         delete _extra_xml;
1295                         _extra_xml = new XMLNode (*child);
1296                         break;
1297                 }
1298         }
1299
1300         if (send) {
1301                 cerr << _name << ": final change to be sent: " << hex << what_changed << dec << endl;
1302                 send_change (what_changed);
1303         }
1304
1305         return 0;
1306 }
1307
1308 int
1309 Region::set_state (const XMLNode& node, int version)
1310 {
1311         const XMLProperty *prop;
1312         Change what_changed = Change (0);
1313
1314         /* ID is not allowed to change, ever */
1315
1316         if ((prop = node.property ("id"))) {
1317                 _id = prop->value();
1318         }
1319
1320         _first_edit = EditChangesNothing;
1321
1322         set_live_state (node, version, what_changed, true);
1323
1324         return 0;
1325 }
1326
1327 void
1328 Region::freeze ()
1329 {
1330         _frozen++;
1331         _last_length = _length;
1332         _last_position = _position;
1333 }
1334
1335 void
1336 Region::thaw ()
1337 {
1338         Change what_changed = Change (0);
1339
1340         {
1341                 Glib::Mutex::Lock lm (_lock);
1342
1343                 if (_frozen && --_frozen > 0) {
1344                         return;
1345                 }
1346
1347                 if (_pending_changed) {
1348                         what_changed = _pending_changed;
1349                         _pending_changed = Change (0);
1350                 }
1351         }
1352
1353         if (what_changed == Change (0)) {
1354                 return;
1355         }
1356
1357         if (what_changed & LengthChanged) {
1358                 if (what_changed & PositionChanged) {
1359                         recompute_at_start ();
1360                 }
1361                 recompute_at_end ();
1362         }
1363
1364         send_change (what_changed);
1365 }
1366
1367 void
1368 Region::send_change (Change what_changed)
1369 {
1370
1371         {
1372                 Glib::Mutex::Lock lm (_lock);
1373                 if (_frozen) {
1374                         _pending_changed = Change (_pending_changed|what_changed);
1375                         return;
1376                 }
1377         }
1378
1379         cerr << _name << " actually sends " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1380         StateChanged (what_changed);
1381         cerr << _name << " done with " << hex << what_changed << dec << " @" << get_microseconds() << endl;
1382
1383         if (!(_flags & DoNotSendPropertyChanges)) {
1384
1385                 /* Try and send a shared_pointer unless this is part of the constructor.
1386                    If so, do nothing.
1387                 */
1388
1389                 try {
1390                         boost::shared_ptr<Region> rptr = shared_from_this();
1391                         cerr << _name << " actually sends prop change " << hex << what_changed << dec <<  " @ " << get_microseconds() << endl;
1392                         RegionPropertyChanged (rptr);
1393                         cerr << _name << " done with prop change  @ " << get_microseconds() << endl;
1394
1395                 } catch (...) {
1396                         /* no shared_ptr available, relax; */
1397                 }
1398         }
1399
1400 }
1401
1402 void
1403 Region::set_last_layer_op (uint64_t when)
1404 {
1405         _last_layer_op = when;
1406 }
1407
1408 bool
1409 Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
1410 {
1411         return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
1412 }
1413
1414 bool
1415 Region::equivalent (boost::shared_ptr<const Region> other) const
1416 {
1417         return _start == other->_start &&
1418                 _position == other->_position &&
1419                 _length == other->_length;
1420 }
1421
1422 bool
1423 Region::size_equivalent (boost::shared_ptr<const Region> other) const
1424 {
1425         return _start == other->_start &&
1426                 _length == other->_length;
1427 }
1428
1429 bool
1430 Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
1431 {
1432         return size_equivalent (other) && source_equivalent (other) && _name == other->_name;
1433 }
1434
1435 void
1436 Region::source_deleted (boost::weak_ptr<Source>)
1437 {
1438         _sources.clear ();
1439
1440         if (!_session.deletion_in_progress()) {
1441                 /* this is a very special case: at least one of the region's
1442                    sources has bee deleted, so invalidate all references to
1443                    ourselves. Do NOT do this during session deletion, because
1444                    then we run the risk that this will actually result
1445                    in this object being deleted (as refcnt goes to zero)
1446                    while emitting DropReferences.
1447                 */
1448
1449                 drop_references ();
1450         }
1451 }
1452
1453 vector<string>
1454 Region::master_source_names ()
1455 {
1456         SourceList::iterator i;
1457
1458         vector<string> names;
1459         for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
1460                 names.push_back((*i)->name());
1461         }
1462
1463         return names;
1464 }
1465
1466 void
1467 Region::set_master_sources (const SourceList& srcs)
1468 {
1469         _master_sources = srcs;
1470         assert (_sources.size() == _master_sources.size());
1471 }
1472
1473 bool
1474 Region::source_equivalent (boost::shared_ptr<const Region> other) const
1475 {
1476         if (!other)
1477                 return false;
1478
1479         SourceList::const_iterator i;
1480         SourceList::const_iterator io;
1481
1482         for (i = _sources.begin(), io = other->_sources.begin(); i != _sources.end() && io != other->_sources.end(); ++i, ++io) {
1483                 if ((*i)->id() != (*io)->id()) {
1484                         return false;
1485                 }
1486         }
1487
1488         for (i = _master_sources.begin(), io = other->_master_sources.begin(); i != _master_sources.end() && io != other->_master_sources.end(); ++i, ++io) {
1489                 if ((*i)->id() != (*io)->id()) {
1490                         return false;
1491                 }
1492         }
1493
1494         return true;
1495 }
1496
1497 bool
1498 Region::uses_source (boost::shared_ptr<const Source> source) const
1499 {
1500         for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
1501                 if (*i == source) {
1502                         return true;
1503                 }
1504         }
1505         return false;
1506 }
1507
1508 sframes_t
1509 Region::source_length(uint32_t n) const
1510 {
1511         return _sources[n]->length(_position - _start);
1512 }
1513
1514 bool
1515 Region::verify_length (nframes_t len)
1516 {
1517         if (source() && (source()->destructive() || source()->length_mutable())) {
1518                 return true;
1519         }
1520
1521         nframes_t maxlen = 0;
1522
1523         for (uint32_t n=0; n < _sources.size(); ++n) {
1524                 maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
1525         }
1526
1527         len = min (len, maxlen);
1528
1529         return true;
1530 }
1531
1532 bool
1533 Region::verify_start_and_length (nframes_t new_start, nframes_t& new_length)
1534 {
1535         if (source() && (source()->destructive() || source()->length_mutable())) {
1536                 return true;
1537         }
1538
1539         nframes_t maxlen = 0;
1540
1541         for (uint32_t n=0; n < _sources.size(); ++n) {
1542                 maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
1543         }
1544
1545         new_length = min (new_length, maxlen);
1546
1547         return true;
1548 }
1549
1550 bool
1551 Region::verify_start (nframes_t pos)
1552 {
1553         if (source() && (source()->destructive() || source()->length_mutable())) {
1554                 return true;
1555         }
1556
1557         for (uint32_t n=0; n < _sources.size(); ++n) {
1558                 if (pos > source_length(n) - _length) {
1559                         return false;
1560                 }
1561         }
1562         return true;
1563 }
1564
1565 bool
1566 Region::verify_start_mutable (nframes_t& new_start)
1567 {
1568         if (source() && (source()->destructive() || source()->length_mutable())) {
1569                 return true;
1570         }
1571
1572         for (uint32_t n=0; n < _sources.size(); ++n) {
1573                 if (new_start > source_length(n) - _length) {
1574                         new_start = source_length(n) - _length;
1575                 }
1576         }
1577         return true;
1578 }
1579
1580 boost::shared_ptr<Region>
1581 Region::get_parent() const
1582 {
1583         boost::shared_ptr<Playlist> pl (playlist());
1584
1585         if (pl) {
1586                 boost::shared_ptr<Region> r;
1587                 boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
1588
1589                 if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
1590                         return boost::static_pointer_cast<Region> (r);
1591                 }
1592         }
1593
1594         return boost::shared_ptr<Region>();
1595 }
1596
1597 int
1598 Region::apply (Filter& filter)
1599 {
1600         return filter.run (shared_from_this());
1601 }
1602
1603
1604 void
1605 Region::invalidate_transients ()
1606 {
1607         _valid_transients = false;
1608         _transients.clear ();
1609 }
1610
1611
1612 void
1613 Region::use_sources (SourceList const & s)
1614 {
1615         set<boost::shared_ptr<Source> > unique_srcs;
1616
1617         for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1618                 _sources.push_back (*i);
1619                 (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1620                 unique_srcs.insert (*i);
1621         }
1622
1623         for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
1624                 _master_sources.push_back (*i);
1625                 if (unique_srcs.find (*i) == unique_srcs.end()) {
1626                         (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
1627                 }
1628         }
1629 }
1630