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