Fix restoration of MementoCommand<Crossfade>. Fixes #3418.
[ardour.git] / libs / ardour / crossfade.cc
1 /*
2     Copyright (C) 2003-2006 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
21 #include "pbd/stacktrace.h"
22
23 #include "ardour/debug.h"
24 #include "ardour/types.h"
25 #include "ardour/crossfade.h"
26 #include "ardour/crossfade_compare.h"
27 #include "ardour/audioregion.h"
28 #include "ardour/playlist.h"
29 #include "ardour/utils.h"
30 #include "ardour/session.h"
31 #include "ardour/source.h"
32 #include "ardour/region_factory.h"
33
34 #include "i18n.h"
35 #include <locale.h>
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace PBD;
40
41 framecnt_t Crossfade::_short_xfade_length = 0;
42
43 /* XXX if and when we ever implement parallel processing of the process()
44    callback, these will need to be handled on a per-thread basis.
45 */
46
47 Sample* Crossfade::crossfade_buffer_out = 0;
48 Sample* Crossfade::crossfade_buffer_in = 0;
49
50
51 #define CROSSFADE_DEFAULT_PROPERTIES \
52         _active (Properties::active, _session.config.get_xfades_active ()) \
53         , _follow_overlap (Properties::follow_overlap, false)
54
55
56 namespace ARDOUR {
57         namespace Properties {
58                 PropertyDescriptor<bool> follow_overlap;
59         }
60 }
61
62 void
63 Crossfade::make_property_quarks ()
64 {
65         Properties::follow_overlap.property_id = g_quark_from_static_string (X_("follow-overlap"));
66         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for follow-overlap = %1\n",      Properties::follow_overlap.property_id));
67 }
68
69 void
70 Crossfade::set_buffer_size (framecnt_t sz)
71 {
72         delete [] crossfade_buffer_out;
73         crossfade_buffer_out = 0;
74
75         delete [] crossfade_buffer_in;
76         crossfade_buffer_in = 0;
77
78         if (sz) {
79                 crossfade_buffer_out = new Sample[sz];
80                 crossfade_buffer_in = new Sample[sz];
81         }
82 }
83
84 bool
85 Crossfade::operator== (const Crossfade& other)
86 {
87         return (_in == other._in) && (_out == other._out);
88 }
89
90 Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<AudioRegion> out,
91                       framecnt_t length,
92                       framepos_t position,
93                       AnchorPoint ap)
94         : AudioRegion (in->session(), position, length, in->name() + string ("<>") + out->name())
95         , CROSSFADE_DEFAULT_PROPERTIES
96         , _fade_in (Evoral::Parameter(FadeInAutomation)) // linear (gain coefficient) => -inf..+6dB
97         , _fade_out (Evoral::Parameter(FadeOutAutomation)) // linear (gain coefficient) => -inf..+6dB
98
99 {
100         _in = in;
101         _out = out;
102         _anchor_point = ap;
103         _fixed = true;
104         _follow_overlap = false;
105
106         initialize ();
107 }
108
109 Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model, bool act)
110         : AudioRegion (a->session(), 0, 0, a->name() + string ("<>") + b->name())
111         , CROSSFADE_DEFAULT_PROPERTIES
112         , _fade_in (Evoral::Parameter(FadeInAutomation)) // linear (gain coefficient) => -inf..+6dB
113         , _fade_out (Evoral::Parameter(FadeOutAutomation)) // linear (gain coefficient) => -inf..+6dB
114 {
115         _in_update = false;
116         _fixed = false;
117         _follow_overlap = false;
118
119         if (compute (a, b, model)) {
120                 throw failed_constructor();
121         }
122
123         _active = act;
124
125         initialize ();
126 }
127
128 Crossfade::Crossfade (const Playlist& playlist, XMLNode const & node)
129         : AudioRegion (playlist.session(), 0, 0, "unnamed crossfade")
130         , CROSSFADE_DEFAULT_PROPERTIES
131         , _fade_in (Evoral::Parameter(FadeInAutomation)) // linear (gain coefficient) => -inf..+6dB
132         , _fade_out (Evoral::Parameter(FadeOutAutomation)) // linear (gain coefficient) => -inf..+6dB
133
134 {
135         boost::shared_ptr<Region> r;
136         XMLProperty const * prop;
137         LocaleGuard lg (X_("POSIX"));
138
139         /* we have to find the in/out regions before we can do anything else */
140
141         if ((prop = node.property ("in")) == 0) {
142                 error << _("Crossfade: no \"in\" region in state") << endmsg;
143                 throw failed_constructor();
144         }
145
146         PBD::ID id (prop->value());
147
148         r = playlist.find_region (id);
149
150         if (!r) {
151                 /* the `in' region is not in a playlist, which probably means that this crossfade
152                    is in the undo record, so we have to find the region in the global region map.
153                 */
154                 r = RegionFactory::region_by_id (id);
155         }
156         
157         if (!r) {
158                 error << string_compose (_("Crossfade: no \"in\" region %1 found in playlist %2 nor in region map"), id, playlist.name())
159                       << endmsg;
160                 throw failed_constructor();
161         }
162
163         if ((_in = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
164                 throw failed_constructor();
165         }
166
167         if ((prop = node.property ("out")) == 0) {
168                 error << _("Crossfade: no \"out\" region in state") << endmsg;
169                 throw failed_constructor();
170         }
171
172         PBD::ID id2 (prop->value());
173
174         r = playlist.find_region (id2);
175
176         if (!r) {
177                 r = RegionFactory::region_by_id (id2);
178         }
179         
180         if (!r) {
181                 error << string_compose (_("Crossfade: no \"out\" region %1 found in playlist %2 nor in region map"), id2, playlist.name())
182                       << endmsg;
183                 throw failed_constructor();
184         }
185
186         if ((_out = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
187                 throw failed_constructor();
188         }
189
190         _length = 0;
191         initialize();
192         _active = true;
193
194         if (set_state (node, Stateful::loading_state_version)) {
195                 throw failed_constructor();
196         }
197 }
198
199 Crossfade::Crossfade (boost::shared_ptr<Crossfade> orig, boost::shared_ptr<AudioRegion> newin, boost::shared_ptr<AudioRegion> newout)
200         : AudioRegion (boost::dynamic_pointer_cast<const AudioRegion> (orig), 0, true)
201         , CROSSFADE_DEFAULT_PROPERTIES
202         , _fade_in (orig->_fade_in)
203         , _fade_out (orig->_fade_out)
204 {
205         _active           = orig->_active;
206         _in_update        = orig->_in_update;
207         _anchor_point     = orig->_anchor_point;
208         _follow_overlap   = orig->_follow_overlap;
209         _fixed            = orig->_fixed;
210
211         _in = newin;
212         _out = newout;
213
214         // copied from Crossfade::initialize()
215         _in_update = false;
216
217         _out->suspend_fade_out ();
218         _in->suspend_fade_in ();
219
220         overlap_type = _in->coverage (_out->position(), _out->last_frame());
221         layer_relation = (int32_t) (_in->layer() - _out->layer());
222
223         // Let's make sure the fade isn't too long
224         set_xfade_length(_length);
225 }
226
227
228 Crossfade::~Crossfade ()
229 {
230 }
231
232 void
233 Crossfade::initialize ()
234 {
235         /* merge source lists from regions */
236
237         _sources = _in->sources();
238         _sources.insert (_sources.end(), _out->sources().begin(), _out->sources().end());
239
240         for (SourceList::iterator i = _sources.begin(); i != _sources.end(); ++i) {
241                 (*i)->inc_use_count ();
242         }
243         
244         _master_sources = _in->master_sources();
245         _master_sources.insert(_master_sources.end(), _out->master_sources().begin(), _out->master_sources().end());
246
247         for (SourceList::iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
248                 (*i)->inc_use_count ();
249         }
250
251         _in_update = false;
252
253         _out->suspend_fade_out ();
254         _in->suspend_fade_in ();
255
256         _fade_out.freeze ();
257         _fade_out.clear ();
258
259 #define EQUAL_POWER_MINUS_3DB
260 #ifdef  EQUAL_POWER_MINUS_3DB
261
262         _fade_out.add ((_length * 0.000000), 1.000000);
263         _fade_out.add ((_length * 0.166667), 0.948859);
264         _fade_out.add ((_length * 0.333333), 0.851507);
265         _fade_out.add ((_length * 0.500000), 0.707946);
266         _fade_out.add ((_length * 0.666667), 0.518174);
267         _fade_out.add ((_length * 0.833333), 0.282192);
268         _fade_out.add ((_length * 1.000000), 0.000000);
269
270 #else // EQUAL_POWER_MINUS_6DB
271
272         _fade_out.add ((_length * 0.000000), 1.000000);
273         _fade_out.add ((_length * 0.166667), 0.833033);
274         _fade_out.add ((_length * 0.333333), 0.666186);
275         _fade_out.add ((_length * 0.500000), 0.499459);
276         _fade_out.add ((_length * 0.666667), 0.332853);
277         _fade_out.add ((_length * 0.833333), 0.166366);
278         _fade_out.add ((_length * 1.000000), 0.000000);
279 #endif
280
281         _fade_out.thaw ();
282
283         _fade_in.freeze ();
284         _fade_in.clear ();
285
286 #define EQUAL_POWER_MINUS_3DB
287 #ifdef  EQUAL_POWER_MINUS_3DB
288
289         _fade_in.add ((_length * 0.000000), 0.000000);
290         _fade_in.add ((_length * 0.166667), 0.282192);
291         _fade_in.add ((_length * 0.333333), 0.518174);
292         _fade_in.add ((_length * 0.500000), 0.707946);
293         _fade_in.add ((_length * 0.666667), 0.851507);
294         _fade_in.add ((_length * 0.833333), 0.948859);
295         _fade_in.add ((_length * 1.000000), 1.000000);
296
297 #else // EQUAL_POWER_MINUS_SIX_DB
298
299         _fade_in.add ((_length * 0.000000), 0.000000);
300         _fade_in.add ((_length * 0.166667), 0.166366);
301         _fade_in.add ((_length * 0.333333), 0.332853);
302         _fade_in.add ((_length * 0.500000), 0.499459);
303         _fade_in.add ((_length * 0.666667), 0.666186);
304         _fade_in.add ((_length * 0.833333), 0.833033);
305         _fade_in.add ((_length * 1.000000), 1.000000);
306
307 #endif
308
309         _fade_in.thaw ();
310
311         overlap_type = _in->coverage (_out->position(), _out->last_frame());
312         layer_relation = (int32_t) (_in->layer() - _out->layer());
313 }
314
315 framecnt_t
316 Crossfade::read_raw_internal (Sample* buf, framecnt_t start, framecnt_t cnt, int channel) const
317 {
318         Sample* mixdown = new Sample[cnt];
319         float* gain = new float[cnt];
320         framecnt_t ret;
321         
322         ret = read_at (buf, mixdown, gain, start, cnt, channel, cnt);
323
324         delete [] mixdown;
325         delete [] gain;
326
327         return ret;
328 }
329
330 framecnt_t
331 Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
332                     float *gain_buffer, framepos_t start, framecnt_t cnt, uint32_t chan_n,
333                     framecnt_t read_frames, framecnt_t skip_frames) const
334 {
335         frameoffset_t offset;
336         framecnt_t to_write;
337
338         if (!_active) {
339                 return 0;
340         }
341
342         if (start < _position) {
343
344                 /* handle an initial section of the read area that we do not
345                    cover.
346                 */
347
348                 offset = _position - start;
349
350                 if (offset < cnt) {
351                         cnt -= offset;
352                 } else {
353                         return 0;
354                 }
355
356                 start = _position;
357                 buf += offset;
358                 to_write = min (_length.val(), (nframes64_t) cnt);
359
360         } else {
361
362                 to_write = min ((_length - (start - _position)), cnt);
363
364         }
365
366         offset = start - _position;
367
368         /* Prevent data from piling up inthe crossfade buffers when reading a transparent region */
369         if (!(_out->opaque())) {
370                 memset (crossfade_buffer_out, 0, sizeof (Sample) * to_write);
371         } else if (!(_in->opaque())) {
372                 memset (crossfade_buffer_in, 0, sizeof (Sample) * to_write);
373         }
374
375         _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
376         _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
377
378         float* fiv = new float[to_write];
379         float* fov = new float[to_write];
380
381         _fade_in.curve().get_vector (offset, offset+to_write, fiv, to_write);
382         _fade_out.curve().get_vector (offset, offset+to_write, fov, to_write);
383
384         /* note: although we have not explicitly taken into account the return values
385            from _out->read_at() or _in->read_at(), the length() function does this
386            implicitly. why? because it computes a value based on the in+out regions'
387            position and length, and so we know precisely how much data they could return.
388         */
389
390         for (framecnt_t n = 0; n < to_write; ++n) {
391                 buf[n] = (crossfade_buffer_out[n] * fov[n]) + (crossfade_buffer_in[n] * fiv[n]);
392         }
393
394         delete [] fov;
395         delete [] fiv;
396
397         return to_write;
398 }
399
400 OverlapType
401 Crossfade::coverage (framepos_t start, framepos_t end) const
402 {
403         framepos_t my_end = _position + _length;
404
405         if ((start >= _position) && (end <= my_end)) {
406                 return OverlapInternal;
407         }
408         if ((end >= _position) && (end <= my_end)) {
409                 return OverlapStart;
410         }
411         if ((start >= _position) && (start <= my_end)) {
412                 return OverlapEnd;
413         }
414         if ((_position >= start) && (_position <= end) && (my_end <= end)) {
415                 return OverlapExternal;
416         }
417         return OverlapNone;
418 }
419
420 void
421 Crossfade::set_active (bool yn)
422 {
423         if (_active != yn) {
424                 _active = yn;
425                 PropertyChanged (PropertyChange (Properties::active));
426         }
427 }
428
429 bool
430 Crossfade::refresh ()
431 {
432         /* crossfades must be between non-muted regions */
433
434         if (_out->muted() || _in->muted()) {
435                 Invalidated (shared_from_this ());
436                 return false;
437         }
438
439         /* Top layer shouldn't be transparent */
440
441         if (!((layer_relation > 0 ? _in : _out)->opaque())) {
442                 Invalidated (shared_from_this());
443                 return false;
444         }
445
446         /* layer ordering cannot change */
447
448         int32_t new_layer_relation = (int32_t) (_in->layer() - _out->layer());
449
450         if (new_layer_relation * layer_relation < 0) { // different sign, layers rotated
451                 Invalidated (shared_from_this ());
452                 return false;
453         }
454
455         OverlapType ot = _in->coverage (_out->first_frame(), _out->last_frame());
456
457         if (ot == OverlapNone) {
458                 Invalidated (shared_from_this ());
459                 return false;
460         }
461
462         bool send_signal;
463
464         if (ot != overlap_type) {
465
466                 if (_follow_overlap) {
467
468                         try {
469                                 compute (_in, _out, _session.config.get_xfade_model());
470                         }
471
472                         catch (NoCrossfadeHere& err) {
473                                 Invalidated (shared_from_this ());
474                                 return false;
475                         }
476
477                         send_signal = true;
478
479                 } else {
480                         Invalidated (shared_from_this ());
481                         return false;
482                 }
483
484         } else {
485
486                 send_signal = update ();
487         }
488
489         if (send_signal) {
490                 PropertyChange bounds;
491                 bounds.add (Properties::start);
492                 bounds.add (Properties::position);
493                 bounds.add (Properties::length);
494                 PropertyChanged (bounds); /* EMIT SIGNAL */
495         }
496
497         _in_update = false;
498
499         return true;
500 }
501
502 bool
503 Crossfade::update ()
504 {
505         framecnt_t newlen;
506
507         if (_follow_overlap) {
508                 newlen = _out->first_frame() + _out->length() - _in->first_frame();
509         } else {
510                 newlen = _length;
511         }
512
513         if (newlen == 0) {
514                 Invalidated (shared_from_this ());
515                 return false;
516         }
517
518         _in_update = true;
519
520         if ((_follow_overlap && newlen != _length) || (_length > newlen)) {
521
522                 double factor =  newlen / (double) _length;
523
524                 _fade_out.x_scale (factor);
525                 _fade_in.x_scale (factor);
526
527                 _length = newlen;
528         }
529
530         switch (_anchor_point) {
531         case StartOfIn:
532                 _position = _in->first_frame();
533                 break;
534
535         case EndOfIn:
536                 _position = _in->last_frame() - _length;
537                 break;
538
539         case EndOfOut:
540                 _position = _out->last_frame() - _length;
541         }
542
543         return true;
544 }
545
546 int
547 Crossfade::compute (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model)
548 {
549         boost::shared_ptr<AudioRegion> top;
550         boost::shared_ptr<AudioRegion> bottom;
551         framecnt_t short_xfade_length;
552
553         short_xfade_length = _short_xfade_length;
554
555         if (a->layer() < b->layer()) {
556                 top = b;
557                 bottom = a;
558         } else {
559                 top = a;
560                 bottom = b;
561         }
562
563         /* first check for matching ends */
564
565         if (top->first_frame() == bottom->first_frame()) {
566
567                 /* Both regions start at the same point */
568
569                 if (top->last_frame() < bottom->last_frame()) {
570
571                         /* top ends before bottom, so put an xfade
572                            in at the end of top.
573                         */
574
575                         /* [-------- top ---------- ]
576                          * {====== bottom =====================}
577                          */
578
579                         _in = bottom;
580                         _out = top;
581
582                         if (top->last_frame() < short_xfade_length) {
583                                 _position = 0;
584                         } else {
585                                 _position = top->last_frame() - short_xfade_length;
586                         }
587
588                         _length = min (short_xfade_length, top->length());
589                         _follow_overlap = false;
590                         _anchor_point = EndOfIn;
591                         _active = true;
592                         _fixed = true;
593
594                 } else {
595                         /* top ends after (or same time) as bottom - no xfade
596                          */
597
598                         /* [-------- top ------------------------ ]
599                          * {====== bottom =====================}
600                          */
601
602                         throw NoCrossfadeHere();
603                 }
604
605         } else if (top->last_frame() == bottom->last_frame()) {
606
607                 /* Both regions end at the same point */
608
609                 if (top->first_frame() > bottom->first_frame()) {
610
611                         /* top starts after bottom, put an xfade in at the
612                            start of top
613                         */
614
615                         /*            [-------- top ---------- ]
616                          * {====== bottom =====================}
617                          */
618
619                         _in = top;
620                         _out = bottom;
621                         _position = top->first_frame();
622                         _length = min (short_xfade_length, top->length());
623                         _follow_overlap = false;
624                         _anchor_point = StartOfIn;
625                         _active = true;
626                         _fixed = true;
627
628                 } else {
629                         /* top starts before bottom - no xfade
630                          */
631
632                         /* [-------- top ------------------------ ]
633                          *    {====== bottom =====================}
634                          */
635
636                         throw NoCrossfadeHere();
637                 }
638
639         } else {
640
641                 /* OK, time to do more regular overlapping */
642
643                 OverlapType ot = top->coverage (bottom->first_frame(), bottom->last_frame());
644
645                 switch (ot) {
646                 case OverlapNone:
647                         /* should be NOTREACHED as a precondition of creating
648                            a new crossfade, but we need to handle it here.
649                         */
650                         throw NoCrossfadeHere();
651                         break;
652
653                 case OverlapInternal:
654                 case OverlapExternal:
655                         /* should be NOTREACHED because of tests above */
656                         throw NoCrossfadeHere();
657                         break;
658
659                 case OverlapEnd: /* top covers start of bottom but ends within it */
660
661                         /* [---- top ------------------------]
662                          *                { ==== bottom ============ }
663                          */
664
665                         _in = bottom;
666                         _out = top;
667                         _anchor_point = EndOfOut;
668
669                         if (model == FullCrossfade) {
670                                 _position = bottom->first_frame(); // "{"
671                                 _length = _out->first_frame() + _out->length() - _in->first_frame();
672                                 /* leave active alone */
673                                 _follow_overlap = true;
674                         } else {
675                                 _length = min (short_xfade_length, top->length());
676                                 _position = top->last_frame() - _length;  // "]" - length
677                                 _active = true;
678                                 _follow_overlap = false;
679
680                         }
681                         break;
682
683                 case OverlapStart:   /* top starts within bottom but covers bottom's end */
684
685                         /*                   { ==== top ============ }
686                          *   [---- bottom -------------------]
687                          */
688
689                         _in = top;
690                         _out = bottom;
691                         _position = top->first_frame();
692                         _anchor_point = StartOfIn;
693
694                         if (model == FullCrossfade) {
695                                 _length = _out->first_frame() + _out->length() - _in->first_frame();
696                                 /* leave active alone */
697                                 _follow_overlap = true;
698                         } else {
699                                 _length = min (short_xfade_length, top->length());
700                                 _active = true;
701                                 _follow_overlap = false;
702
703                         }
704
705                         break;
706                 }
707         }
708
709         return 0;
710 }
711
712 XMLNode&
713 Crossfade::get_state ()
714 {
715         XMLNode* node = new XMLNode (X_("Crossfade"));
716         XMLNode* child;
717         char buf[64];
718         LocaleGuard lg (X_("POSIX"));
719
720         id().print (buf, sizeof (buf));
721         node->add_property ("id", buf);
722         _out->id().print (buf, sizeof (buf));
723         node->add_property ("out", buf);
724         _in->id().print (buf, sizeof (buf));
725         node->add_property ("in", buf);
726         node->add_property ("active", (_active ? "yes" : "no"));
727         node->add_property ("follow-overlap", (_follow_overlap ? "yes" : "no"));
728         node->add_property ("fixed", (_fixed ? "yes" : "no"));
729         snprintf (buf, sizeof(buf), "%" PRId64, _length.val());
730         node->add_property ("length", buf);
731         snprintf (buf, sizeof(buf), "%" PRIu32, (uint32_t) _anchor_point);
732         node->add_property ("anchor-point", buf);
733         snprintf (buf, sizeof(buf), "%" PRId64, _position.val());
734         node->add_property ("position", buf);
735
736         child = node->add_child ("FadeIn");
737
738         for (AutomationList::iterator ii = _fade_in.begin(); ii != _fade_in.end(); ++ii) {
739                 XMLNode* pnode;
740
741                 pnode = new XMLNode ("point");
742
743                 snprintf (buf, sizeof (buf), "%" PRId64, (framepos_t) floor ((*ii)->when));
744                 pnode->add_property ("x", buf);
745                 snprintf (buf, sizeof (buf), "%.12g", (*ii)->value);
746                 pnode->add_property ("y", buf);
747                 child->add_child_nocopy (*pnode);
748         }
749
750         child = node->add_child ("FadeOut");
751
752         for (AutomationList::iterator ii = _fade_out.begin(); ii != _fade_out.end(); ++ii) {
753                 XMLNode* pnode;
754
755                 pnode = new XMLNode ("point");
756
757                 snprintf (buf, sizeof (buf), "%" PRId64, (framepos_t) floor ((*ii)->when));
758                 pnode->add_property ("x", buf);
759                 snprintf (buf, sizeof (buf), "%.12g", (*ii)->value);
760                 pnode->add_property ("y", buf);
761                 child->add_child_nocopy (*pnode);
762         }
763
764         return *node;
765 }
766
767 int
768 Crossfade::set_state (const XMLNode& node, int /*version*/)
769 {
770         XMLNodeConstIterator i;
771         XMLNodeList children;
772         XMLNode* fi;
773         XMLNode* fo;
774         const XMLProperty* prop;
775         LocaleGuard lg (X_("POSIX"));
776         PropertyChange what_changed;
777         framepos_t val;
778
779         if ((prop = node.property (X_("id")))) {
780                 _id = prop->value();
781         }
782
783         if ((prop = node.property ("position")) != 0) {
784                 sscanf (prop->value().c_str(), "%" PRId64, &val);
785                 if (val != _position) {
786                         _position = val;
787                         what_changed.add (Properties::position);
788                 }
789         } else {
790                 warning << _("old-style crossfade information - no position information") << endmsg;
791                 _position = _in->first_frame();
792         }
793
794         if ((prop = node.property ("active")) != 0) {
795                 bool x = string_is_affirmative (prop->value());
796                 if (x != _active) {
797                         _active = x;
798                         what_changed.add (Properties::active);
799                 }
800         } else {
801                 _active = true;
802         }
803
804         if ((prop = node.property ("follow-overlap")) != 0) {
805                 _follow_overlap = string_is_affirmative (prop->value());
806         } else {
807                 _follow_overlap = false;
808         }
809
810         if ((prop = node.property ("fixed")) != 0) {
811                 _fixed = string_is_affirmative (prop->value());
812         } else {
813                 _fixed = false;
814         }
815
816         if ((prop = node.property ("anchor-point")) != 0) {
817                 _anchor_point = AnchorPoint (atoi ((prop->value().c_str())));
818         } else {
819                 _anchor_point = StartOfIn;
820         }
821
822         if ((prop = node.property ("length")) != 0) {
823
824                 sscanf (prop->value().c_str(), "%" PRId64, &val);
825                 if (val != _length) {
826                         _length = val;
827                         what_changed.add (Properties::length);
828                 }
829
830         } else {
831
832                 /* XXX this branch is legacy code from before
833                    the point where we stored xfade lengths.
834                 */
835
836                 if ((_length = overlap_length()) == 0) {
837                         throw failed_constructor();
838                 }
839         }
840
841         if ((fi = find_named_node (node, "FadeIn")) == 0) {
842                 return -1;
843         }
844
845         if ((fo = find_named_node (node, "FadeOut")) == 0) {
846                 return -1;
847         }
848
849         /* fade in */
850
851         _fade_in.freeze ();
852         _fade_in.clear ();
853
854         children = fi->children();
855
856         for (i = children.begin(); i != children.end(); ++i) {
857                 if ((*i)->name() == "point") {
858                         framepos_t x;
859                         float y;
860
861                         prop = (*i)->property ("x");
862                         sscanf (prop->value().c_str(), "%" PRId64, &x);
863
864                         prop = (*i)->property ("y");
865                         sscanf (prop->value().c_str(), "%f", &y);
866
867                         _fade_in.add (x, y);
868                 }
869         }
870
871         _fade_in.front()->value = 0.0;
872         _fade_in.back()->value = 1.0;
873
874         _fade_in.thaw ();
875
876         /* fade out */
877
878         _fade_out.freeze ();
879         _fade_out.clear ();
880
881         children = fo->children();
882
883         for (i = children.begin(); i != children.end(); ++i) {
884                 if ((*i)->name() == "point") {
885                         framepos_t x;
886                         float y;
887                         XMLProperty* prop;
888
889                         prop = (*i)->property ("x");
890                         sscanf (prop->value().c_str(), "%" PRId64, &x);
891
892                         prop = (*i)->property ("y");
893                         sscanf (prop->value().c_str(), "%f", &y);
894
895                         _fade_out.add (x, y);
896                 }
897         }
898
899         _fade_out.front()->value = 1.0;
900         _fade_out.back()->value = 0.0;
901
902         _fade_out.thaw ();
903
904         PropertyChanged (what_changed); /* EMIT SIGNAL */
905         FadesChanged (); /* EMIT SIGNAL */
906
907         return 0;
908 }
909
910 bool
911 Crossfade::can_follow_overlap () const
912 {
913         return !_fixed;
914 }
915
916 void
917 Crossfade::set_follow_overlap (bool yn)
918 {
919         if (yn == _follow_overlap || _fixed) {
920                 return;
921         }
922
923         _follow_overlap = yn;
924
925         if (!yn) {
926                 set_xfade_length (_short_xfade_length);
927         } else {
928                 set_xfade_length (_out->first_frame() + _out->length() - _in->first_frame());
929         }
930
931         PropertyChanged (PropertyChange (Properties::follow_overlap));
932 }
933
934 framecnt_t
935 Crossfade::set_xfade_length (framecnt_t len)
936 {
937         framecnt_t limit = 0;
938
939         switch (_anchor_point) {
940         case StartOfIn:
941                 limit = _in->length();
942                 break;
943
944         case EndOfIn:
945                 limit = _in->length();
946                 break;
947
948         case EndOfOut:
949                 limit = _out->length();
950                 break;
951
952         }
953
954         len = min (limit, len);
955
956         double factor = len / (double) _length;
957
958         _in_update = true;
959         _fade_out.x_scale (factor);
960         _fade_in.x_scale (factor);
961         _in_update = false;
962
963         _length = len;
964
965         PropertyChanged (PropertyChange (Properties::length));
966         
967         return len;
968 }
969
970 framecnt_t
971 Crossfade::overlap_length () const
972 {
973         if (_fixed) {
974                 return _length;
975         }
976         return _out->first_frame() + _out->length() - _in->first_frame();
977 }
978
979 void
980 Crossfade::set_short_xfade_length (framecnt_t n)
981 {
982         _short_xfade_length = n;
983 }