67ccea937182d4953fc6017454f554a9a1fc6cd0
[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         _out->id().print (buf, sizeof (buf));
721         node->add_property ("out", buf);
722         _in->id().print (buf, sizeof (buf));
723         node->add_property ("in", buf);
724         node->add_property ("active", (_active ? "yes" : "no"));
725         node->add_property ("follow-overlap", (_follow_overlap ? "yes" : "no"));
726         node->add_property ("fixed", (_fixed ? "yes" : "no"));
727         snprintf (buf, sizeof(buf), "%" PRId64, _length.val());
728         node->add_property ("length", buf);
729         snprintf (buf, sizeof(buf), "%" PRIu32, (uint32_t) _anchor_point);
730         node->add_property ("anchor-point", buf);
731         snprintf (buf, sizeof(buf), "%" PRId64, _position.val());
732         node->add_property ("position", buf);
733
734         child = node->add_child ("FadeIn");
735
736         for (AutomationList::iterator ii = _fade_in.begin(); ii != _fade_in.end(); ++ii) {
737                 XMLNode* pnode;
738
739                 pnode = new XMLNode ("point");
740
741                 snprintf (buf, sizeof (buf), "%" PRId64, (framepos_t) floor ((*ii)->when));
742                 pnode->add_property ("x", buf);
743                 snprintf (buf, sizeof (buf), "%.12g", (*ii)->value);
744                 pnode->add_property ("y", buf);
745                 child->add_child_nocopy (*pnode);
746         }
747
748         child = node->add_child ("FadeOut");
749
750         for (AutomationList::iterator ii = _fade_out.begin(); ii != _fade_out.end(); ++ii) {
751                 XMLNode* pnode;
752
753                 pnode = new XMLNode ("point");
754
755                 snprintf (buf, sizeof (buf), "%" PRId64, (framepos_t) floor ((*ii)->when));
756                 pnode->add_property ("x", buf);
757                 snprintf (buf, sizeof (buf), "%.12g", (*ii)->value);
758                 pnode->add_property ("y", buf);
759                 child->add_child_nocopy (*pnode);
760         }
761
762         return *node;
763 }
764
765 int
766 Crossfade::set_state (const XMLNode& node, int /*version*/)
767 {
768         XMLNodeConstIterator i;
769         XMLNodeList children;
770         XMLNode* fi;
771         XMLNode* fo;
772         const XMLProperty* prop;
773         LocaleGuard lg (X_("POSIX"));
774         PropertyChange what_changed;
775         framepos_t val;
776
777         if ((prop = node.property ("position")) != 0) {
778                 sscanf (prop->value().c_str(), "%" PRId64, &val);
779                 if (val != _position) {
780                         _position = val;
781                         what_changed.add (Properties::position);
782                 }
783         } else {
784                 warning << _("old-style crossfade information - no position information") << endmsg;
785                 _position = _in->first_frame();
786         }
787
788         if ((prop = node.property ("active")) != 0) {
789                 bool x = string_is_affirmative (prop->value());
790                 if (x != _active) {
791                         _active = x;
792                         what_changed.add (Properties::active);
793                 }
794         } else {
795                 _active = true;
796         }
797
798         if ((prop = node.property ("follow-overlap")) != 0) {
799                 _follow_overlap = string_is_affirmative (prop->value());
800         } else {
801                 _follow_overlap = false;
802         }
803
804         if ((prop = node.property ("fixed")) != 0) {
805                 _fixed = string_is_affirmative (prop->value());
806         } else {
807                 _fixed = false;
808         }
809
810         if ((prop = node.property ("anchor-point")) != 0) {
811                 _anchor_point = AnchorPoint (atoi ((prop->value().c_str())));
812         } else {
813                 _anchor_point = StartOfIn;
814         }
815
816         if ((prop = node.property ("length")) != 0) {
817
818                 sscanf (prop->value().c_str(), "%" PRId64, &val);
819                 if (val != _length) {
820                         _length = val;
821                         what_changed.add (Properties::length);
822                 }
823
824         } else {
825
826                 /* XXX this branch is legacy code from before
827                    the point where we stored xfade lengths.
828                 */
829
830                 if ((_length = overlap_length()) == 0) {
831                         throw failed_constructor();
832                 }
833         }
834
835         if ((fi = find_named_node (node, "FadeIn")) == 0) {
836                 return -1;
837         }
838
839         if ((fo = find_named_node (node, "FadeOut")) == 0) {
840                 return -1;
841         }
842
843         /* fade in */
844
845         _fade_in.freeze ();
846         _fade_in.clear ();
847
848         children = fi->children();
849
850         for (i = children.begin(); i != children.end(); ++i) {
851                 if ((*i)->name() == "point") {
852                         framepos_t x;
853                         float y;
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_in.add (x, y);
862                 }
863         }
864
865         _fade_in.front()->value = 0.0;
866         _fade_in.back()->value = 1.0;
867
868         _fade_in.thaw ();
869
870         /* fade out */
871
872         _fade_out.freeze ();
873         _fade_out.clear ();
874
875         children = fo->children();
876
877         for (i = children.begin(); i != children.end(); ++i) {
878                 if ((*i)->name() == "point") {
879                         framepos_t x;
880                         float y;
881                         XMLProperty* prop;
882
883                         prop = (*i)->property ("x");
884                         sscanf (prop->value().c_str(), "%" PRId64, &x);
885
886                         prop = (*i)->property ("y");
887                         sscanf (prop->value().c_str(), "%f", &y);
888
889                         _fade_out.add (x, y);
890                 }
891         }
892
893         _fade_out.front()->value = 1.0;
894         _fade_out.back()->value = 0.0;
895
896         _fade_out.thaw ();
897
898         PropertyChanged (what_changed); /* EMIT SIGNAL */
899         FadesChanged (); /* EMIT SIGNAL */
900
901         return 0;
902 }
903
904 bool
905 Crossfade::can_follow_overlap () const
906 {
907         return !_fixed;
908 }
909
910 void
911 Crossfade::set_follow_overlap (bool yn)
912 {
913         if (yn == _follow_overlap || _fixed) {
914                 return;
915         }
916
917         _follow_overlap = yn;
918
919         if (!yn) {
920                 set_xfade_length (_short_xfade_length);
921         } else {
922                 set_xfade_length (_out->first_frame() + _out->length() - _in->first_frame());
923         }
924
925         PropertyChanged (PropertyChange (Properties::follow_overlap));
926 }
927
928 framecnt_t
929 Crossfade::set_xfade_length (framecnt_t len)
930 {
931         framecnt_t limit = 0;
932
933         switch (_anchor_point) {
934         case StartOfIn:
935                 limit = _in->length();
936                 break;
937
938         case EndOfIn:
939                 limit = _in->length();
940                 break;
941
942         case EndOfOut:
943                 limit = _out->length();
944                 break;
945
946         }
947
948         len = min (limit, len);
949
950         double factor = len / (double) _length;
951
952         _in_update = true;
953         _fade_out.x_scale (factor);
954         _fade_in.x_scale (factor);
955         _in_update = false;
956
957         _length = len;
958
959         PropertyChanged (PropertyChange (Properties::length));
960         
961         return len;
962 }
963
964 framecnt_t
965 Crossfade::overlap_length () const
966 {
967         if (_fixed) {
968                 return _length;
969         }
970         return _out->first_frame() + _out->length() - _in->first_frame();
971 }
972
973 void
974 Crossfade::set_short_xfade_length (framecnt_t n)
975 {
976         _short_xfade_length = n;
977 }