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