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